Fixes, IP list
This commit is contained in:
parent
d202ad3b05
commit
cd0bf3113e
3 changed files with 119 additions and 43 deletions
124
editor.py
124
editor.py
|
|
@ -2,26 +2,33 @@ import network
|
|||
import tkinter as tk
|
||||
from tkinter import ttk, filedialog, colorchooser
|
||||
import sys
|
||||
import colorsys
|
||||
import random
|
||||
|
||||
def random_color(seed):
|
||||
return "#"+"".join([
|
||||
hex(int(i*255))[2:].zfill(2)
|
||||
for i in colorsys.hsv_to_rgb(random.Random(seed).uniform(0.0, 1.0), 0.8, 1)
|
||||
])
|
||||
|
||||
listen_addr = ("0.0.0.0", int(sys.argv[1]))
|
||||
send_addr = ("192.168.1.255", int(sys.argv[2]))
|
||||
send_addr = ("192.168.0.255", int(sys.argv[2]))
|
||||
|
||||
sock = network.Sock()
|
||||
|
||||
waiting_for_text = True
|
||||
color = "#000000"
|
||||
|
||||
root = tk.Tk()
|
||||
|
||||
def foo():
|
||||
print("foo")
|
||||
root.title("Éditeur en réseau")
|
||||
|
||||
root.option_add('*tearOff', False)
|
||||
menubar = tk.Menu(root)
|
||||
root['menu'] = menubar
|
||||
menu_file = tk.Menu(menubar)
|
||||
menu_edit = tk.Menu(menubar)
|
||||
menubar.add_cascade(menu=menu_file, label='File')
|
||||
menubar.add_cascade(menu=menu_edit, label='Edit')
|
||||
menu_file.add_command(label='New', command=foo)
|
||||
menubar.add_cascade(menu=menu_file, label='Fichier')
|
||||
menubar.add_cascade(menu=menu_edit, label='Édition')
|
||||
|
||||
area = tk.Text(root)
|
||||
area.grid(column=0, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))
|
||||
|
|
@ -30,47 +37,79 @@ area_scrolly = ttk.Scrollbar(root, orient=tk.VERTICAL, command=area.yview)
|
|||
area_scrolly.grid(column=1, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))
|
||||
area.configure(yscrollcommand=area_scrolly.set)
|
||||
|
||||
area_net = tk.Text(root, width=21)
|
||||
area_net["state"] = "disabled"
|
||||
area_net.grid(column=3, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))
|
||||
|
||||
area_net_scrolly = ttk.Scrollbar(root, orient=tk.VERTICAL, command=area_net.yview)
|
||||
area_net_scrolly.grid(column=4, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))
|
||||
area_net.configure(yscrollcommand=area_net_scrolly.set)
|
||||
|
||||
canvas = tk.Canvas(root, background='white')
|
||||
canvas.grid(column=2, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))
|
||||
|
||||
canvas_last_x = 0
|
||||
canvas_last_y = 0
|
||||
|
||||
def on_save_bt():
|
||||
path = tk.filedialog.asksaveasfilename(filetypes=[("Fichier texte", ".txt"), ("Autre", ".*")])
|
||||
if path != "":
|
||||
f = open(path, "w")
|
||||
f.write(area.get("1.0", "end"))
|
||||
f.close()
|
||||
|
||||
def on_open_bt():
|
||||
path = tk.filedialog.askopenfilename(filetypes=[("Fichier texte", ".txt"), ("Autre", ".*")])
|
||||
if path != ():
|
||||
f = open(path, "r")
|
||||
if f:
|
||||
area.replace("1.0", "end", f.read())
|
||||
f.close()
|
||||
|
||||
def on_color_bt():
|
||||
global color
|
||||
color = tk.colorchooser.askcolor(initialcolor=color)[1]
|
||||
|
||||
def canvas_save_pos(event):
|
||||
global canvas_last_x, canvas_last_y
|
||||
canvas_last_x = event.x
|
||||
canvas_last_y = event.y
|
||||
|
||||
def canvas_move(event):
|
||||
canvas.create_line(canvas_last_x, canvas_last_y, event.x, event.y)
|
||||
sock.send({"type":"create_line", "x1":canvas_last_x, "y1":canvas_last_y, "x2":event.x, "y2":event.y}, send_addr)
|
||||
global color
|
||||
canvas.create_line(canvas_last_x, canvas_last_y, event.x, event.y, fill=color)
|
||||
sock.send({
|
||||
"type":"create_line",
|
||||
"x1":canvas_last_x,
|
||||
"y1":canvas_last_y,
|
||||
"x2":event.x,
|
||||
"y2":event.y,
|
||||
"color":color
|
||||
}, send_addr)
|
||||
canvas_save_pos(event)
|
||||
|
||||
def canvas_click(event):
|
||||
print(colorchooser.askcolor(initialcolor='black'))
|
||||
menu_file.add_command(label='Ouvrir', command=on_open_bt)
|
||||
menu_file.add_command(label='Enregistrer', command=on_save_bt)
|
||||
|
||||
canvas.bind("<Button-1>", canvas_save_pos)
|
||||
canvas.bind("<B1-Motion>", canvas_move)
|
||||
canvas.bind("<Button-3>", canvas_click)
|
||||
|
||||
root.rowconfigure(1, weight=1)
|
||||
root.columnconfigure(0, weight=1)
|
||||
root.columnconfigure(2, weight=1)
|
||||
|
||||
def on_save_bt():
|
||||
path = tk.filedialog.asksaveasfilename(filetypes=[("Fichier texte", ".txt")])
|
||||
file = open(path, "w")
|
||||
file.write(area.get("1.0", "end"))
|
||||
|
||||
toolbar = ttk.Frame(root)
|
||||
toolbar.grid(column=0, row=0, columnspan=2, sticky=(tk.N, tk.S, tk.E, tk.W))
|
||||
|
||||
save_bt = ttk.Button(toolbar, text="Enregistrer", command=on_save_bt)
|
||||
save_bt.grid(column=0, row=0, sticky=(tk.W))
|
||||
|
||||
open_bt = ttk.Button(toolbar, text="Ouvrir")
|
||||
open_bt = ttk.Button(toolbar, text="Ouvrir", command=on_open_bt)
|
||||
open_bt.grid(column=1, row=0, sticky=(tk.W))
|
||||
|
||||
color_bt = ttk.Button(toolbar, text="Couleur", command=on_color_bt)
|
||||
color_bt.grid(column=2, row=0, sticky=(tk.W))
|
||||
|
||||
old_text = ""
|
||||
def diff(old, new):
|
||||
if old == new:
|
||||
|
|
@ -101,46 +140,69 @@ def diff(old, new):
|
|||
|
||||
def on_area_input(event):
|
||||
global old_text
|
||||
#print(area.get("1.0", "end"))
|
||||
print(event)
|
||||
#sock.send({"type":"insert", "start":"1.0", "text":area.get("1.0", "end")}, send_addr)
|
||||
#sock.send({"type":"replace", "start":"1.0", "end":"end", "text":area.get("1.0", "end")}, send_addr)
|
||||
d = diff(old_text, area.get("1.0","end"))
|
||||
if d == None:
|
||||
return
|
||||
sock.send(d, send_addr)
|
||||
old_text = area.get("1.0","end")
|
||||
|
||||
#if event.keycode == 25:
|
||||
# area.mark_set("insert", "1.0")
|
||||
|
||||
area.bind("<KeyRelease>", on_area_input)
|
||||
area.bind("<B3-Motion>", on_area_input)
|
||||
|
||||
area.tag_configure("plop", background="#ffaaaa")
|
||||
authors = {}
|
||||
|
||||
def set_author(author):
|
||||
author = author[0]+"."+str(author[1])
|
||||
if author in authors:
|
||||
return author
|
||||
author_color = random_color(author.encode())
|
||||
authors[author] = author_color
|
||||
area.tag_configure(author, background=author_color)
|
||||
area_net.tag_configure(author, background=author_color)
|
||||
area_net["state"] = "normal"
|
||||
area_net.insert("end", author+"\n", author)
|
||||
area_net["state"] = "disabled"
|
||||
return author
|
||||
|
||||
def on_request(r):
|
||||
global waiting_for_text, old_text
|
||||
print(r)
|
||||
c, a = r
|
||||
if type(c) != dict:
|
||||
return
|
||||
if "message" in c:
|
||||
area.replace("1.0", "end", c["message"], set_author(a))
|
||||
waiting_for_text = False
|
||||
old_text = area.get("1.0","end")
|
||||
if not "type" in c:
|
||||
return
|
||||
if c["type"] == "set":
|
||||
if not "text" in c:
|
||||
return
|
||||
if waiting_for_text:
|
||||
area.replace("1.0", "end", c["text"])
|
||||
if c["text"] != "\n":
|
||||
area.replace("1.0", "end", c["text"])
|
||||
waiting_for_text = False
|
||||
old_text = area.get("1.0","end")
|
||||
elif c["type"] == "insert":
|
||||
area.insert(c["start"], c["text"], "plop")
|
||||
if not "text" in c or not "start" in c:
|
||||
return
|
||||
area.insert(c["start"], c["text"], set_author(a))
|
||||
old_text = area.get("1.0","end")
|
||||
elif c["type"] == "replace":
|
||||
area.replace(c["start"], c["end"], c["text"], "plop")
|
||||
if not "text" in c or not "start" in c or not "end" in c:
|
||||
return
|
||||
area.replace(c["start"], c["end"], c["text"], set_author(a))
|
||||
old_text = area.get("1.0","end")
|
||||
elif c["type"] == "get":
|
||||
sock.send({"type":"set", "text":area.get("1.0", "end")}, send_addr)
|
||||
elif c["type"] == "create_line":
|
||||
canvas.create_line(c["x1"], c["y1"], c["x2"], c["y2"])
|
||||
if not "color" in c or not "x1" in c or not "y1" in c or not "x2" in c or not "y2" in c:
|
||||
return
|
||||
canvas.create_line(c["x1"], c["y1"], c["x2"], c["y2"], fill=c["color"])
|
||||
|
||||
sock.listen(listen_addr, on_request)
|
||||
|
||||
sock.send({"type":"get"}, send_addr)
|
||||
#sock.send({"type":"get"}, send_addr)
|
||||
|
||||
root.mainloop()
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ class Sock:
|
|||
self.queue = []
|
||||
self.queue_lock = Lock()
|
||||
self.sock_thread = None
|
||||
self.has_sent = False
|
||||
|
||||
def send_raw(self, message, address):
|
||||
self.has_sent = True
|
||||
if type(message) == str:
|
||||
message = message.encode()
|
||||
if NETTRACE:
|
||||
|
|
@ -21,6 +23,7 @@ class Sock:
|
|||
|
||||
# Envoie une requete
|
||||
def send(self, message, address):
|
||||
self.has_sent = True
|
||||
message = json.dumps(message)
|
||||
if NETTRACE:
|
||||
print("Send to", tuple(address), ":", message, file=sys.stderr)
|
||||
|
|
@ -30,6 +33,8 @@ class Sock:
|
|||
# Si la fonction callback est donnee, elle sera appelee avec les requetes recues.
|
||||
# La methode get ne fonctionnera pas si un callback est defini.
|
||||
def listen(self, address, callback=None, length=65535):
|
||||
if self.has_sent:
|
||||
print("Attention, listen ne fonctionne pas si send a ete appele avant.")
|
||||
self.sock_thread = SockThread(self, tuple(address), length, callback)
|
||||
self.sock_thread.setDaemon(True)
|
||||
self.sock_thread.start()
|
||||
|
|
|
|||
33
tutorial.md
33
tutorial.md
|
|
@ -1,6 +1,14 @@
|
|||
# Tutoriel Tkinter
|
||||
|
||||
Pour aller plus loin : [TkDocs Tutorial](https://tkdocs.com/tutorial/index.html)
|
||||
**Prérequis** :
|
||||
Il faut être un peu à l'aise avec le Python, au moins les variables, fonctions, manipulation des chaînes de caractères.
|
||||
Si ce n'est pas le cas, [France-IOI](https://www.france-ioi.org/algo/chapters.php) propose une introduction ludique au Python.
|
||||
|
||||
Tkinter est une bibliothèque d'interface graphique, qui permet de créer des fenêtres sous Linux, Windows et Mac.
|
||||
C'est une des plus simples à utiliser en Python.
|
||||
Seulement elle est un peu vieille et trop peu intuitive, d'où ce tutoriel qui peut servir de mini-référence.
|
||||
|
||||
Pour aller plus loin : [TkDocs Tutorial](https://tkdocs.com/tutorial/index.html) (en anglais)
|
||||
|
||||
## Code de base
|
||||
|
||||
|
|
@ -64,7 +72,8 @@ On peut appeler plusieurs fois ces fonctions pour choisir plusieurs lignes et co
|
|||
|
||||
## Widgets
|
||||
|
||||
Tous les widgets peuvent être positionnés avec `grid`, de la même manière que ci-dessus.
|
||||
Tous les widgets doivent être positionnés avec `grid`, de la même manière que ci-dessus.
|
||||
Sans ça, ils ne seront pas affichés !
|
||||
|
||||
### Label
|
||||
|
||||
|
|
@ -128,21 +137,21 @@ text = tk.Text(root)
|
|||
Il y a plusieurs méthodes pour interagir avec le texte :
|
||||
|
||||
```python
|
||||
print(area.get("1.0", "end")) # obtenir tout le texte
|
||||
print(area.get("2.0", "8.0")) # le texte de la ligne 2 à la ligne 8
|
||||
area.replace("1.0", "end", "le nouveau texte") # remplacer du texte
|
||||
area.insert("1.0", "le nouveau texte") # insérer du texte
|
||||
area.insert("1.0 +42 chars", "le nouveau texte")
|
||||
area.insert("end -3 lines", "le nouveau texte")
|
||||
print(text.get("1.0", "end")) # obtenir tout le texte
|
||||
print(text.get("2.0", "8.0")) # le texte de la ligne 2 à la ligne 8
|
||||
text.replace("1.0", "end", "le nouveau texte") # remplacer du texte
|
||||
text.insert("1.0", "le nouveau texte") # insérer du texte
|
||||
text.insert("1.0 +42 chars", "le nouveau texte")
|
||||
text.insert("end -3 lines", "le nouveau texte")
|
||||
```
|
||||
|
||||
Pour mettre en forme certaines parties du texte, on peut utiliser des tags :
|
||||
|
||||
```python
|
||||
area.tag_configure("fond_rouge", background="#ffaaaa")
|
||||
area.tag_configure("insistance", foreground="#008800", underline=True)
|
||||
text.tag_configure("fond_rouge", background="#ffaaaa")
|
||||
text.tag_configure("insistance", foreground="#008800", underline=True)
|
||||
|
||||
area.insert("1.0", "ce texte sera sur fond rouge", "fond_rouge")
|
||||
text.insert("1.0", "ce texte sera sur fond rouge", "fond_rouge")
|
||||
text.tag_add("insistance", "1.3", "1.8")
|
||||
```
|
||||
|
||||
|
|
@ -220,7 +229,7 @@ def onrelease(event):
|
|||
print("On a frappé le clavier !")
|
||||
print(event)
|
||||
|
||||
area.bind("<KeyRelease>", onrelease)
|
||||
text.bind("<KeyRelease>", onrelease)
|
||||
```
|
||||
|
||||
On peut aussi utiliser les infos contenues dans l'événement, par exemple `event.keycode`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue