def textFieldConstructor(self, labelText, value): def selectAllText(event): xField = event.widget xField.tag_add(SEL, '1.0', 'end') xField.mark_set(INSERT, "1.0") xField.see(INSERT) return 'break' #Label(self.body, text=labelText).grid(row=0, column=0, sticky='nw') Label(self.body, text=labelText).pack(side=TOP) #xTextbox = Text(self.body) ## ver que width y height poner xTextbox = ScrollText(self.body) #xTextbox.bind('<KeyRelease>', lambda event: apply()) xTextbox.bind('<Control-Key-a>', lambda event: selectAllText(event) ) xTextbox.bind('<Control-Key-A>', lambda event: selectAllText(event) ) #xTextbox.grid(row=1, column=0, sticky='nw') xTextbox.pack(side=BOTTOM, fill=BOTH, expand=True) xTextbox.insert('1.0', value) self.entries[labelText] = xTextbox if self.firstField == None: self.firstField = xTextbox #SQL buttons from module params = {'parent':self.upper, 'field':self.firstField} MOD.runModules('TOPLEVEL', params)
def add_tab(self, text='new', dirty=True): f = ttk.Frame(self.nb) # see http://stackoverflow.com/questions/13832720/how-to-attach-a-scrollbar-to-a-text-widget t = ScrolledText(f, relief=tk.RAISED, wrap=tk.WORD) t.insert(tk.INSERT, text) t.pack(fill=tk.BOTH, expand=1) t.bind("<KeyRelease>", self.update) self.nb.add(f) self.tabs.append(t) self.nb.select(self.nb.tabs()[-1]) self.update(dirty=dirty)
def initializeResponseEntry(): responseEntry = ScrolledText(width=40, height=6, background=darkSalmon) responseEntry.insert(END, 'Type here') responseEntry.grid(row=2, sticky=EW, padx=50) responseEntry.bind('<KeyRelease>', typing) responseEntry.bind('<BackSpace>', blankButtons()) responseEntry.bind('<Button-1>', clearText) return responseEntry
class BlockdiagEditor(object): """ Interactive editor UI for blockdiag """ def __init__(self, diag_method, source, diag_image): self.diag_method = diag_method self.source = intern(source.encode("utf-8")) self.image_format = "PNG" self.tmp = NamedTemporaryFile(mode="wb") self.root = Tk.Tk() self.root.geometry("1024x768") self.root.protocol("WM_DELETE_WINDOW", self.quit) # Frames self.frame = Tk.Frame(self.root) self.frame.master.title("blockdiag editor") self.frame.pack(fill=Tk.BOTH, expand=1, padx=3, pady=3) self.btn_frame = Tk.Frame(self.frame) self.btn_frame.pack(fill=Tk.BOTH, padx=3, pady=3) self.text_frame = Tk.Frame(self.frame) self.text_frame.pack(fill=Tk.BOTH, expand=1, padx=3, pady=3) self.image_frame = Tk.Frame(self.frame) self.image_frame.pack(fill=Tk.BOTH, expand=1, padx=3, pady=3) self.image_frame.grid_rowconfigure(0, weight=1, minsize=0) self.image_frame.grid_columnconfigure(0, weight=1, minsize=0) # Button self.upd_btn = Tk.Button(self.btn_frame, bd=2, text="Update Canvas", command=self.redraw_diag_image) self.upd_btn.pack(side=Tk.LEFT) self.link_btn = Tk.Button(self.btn_frame, bd=2, text="Permanent link", command=self.open_permanent_link) self.link_btn.pack(side=Tk.LEFT) self.quit_btn = Tk.Button(self.btn_frame, bd=2, text="Quit", command=self.quit) self.quit_btn.pack(side=Tk.LEFT) # Text Editor self.text = ScrolledText(self.text_frame, wrap=Tk.WORD) self.text.pack(fill=Tk.BOTH, expand=1) self.text.insert(Tk.END, source) self.text.focus_set() self.text.bind("<KeyRelease-Control_L>", self.redraw_diag_image) self.text.bind("<KeyRelease-Control_R>", self.redraw_diag_image) # Image Viewer self.image = ImageTk.PhotoImage(file=diag_image) self.canvas = Tk.Canvas(self.image_frame, scrollregion=(0, 0, self.image.width(), self.image.height())) self.canvas.grid(row=0, column=0, sticky=Tk.N + Tk.E + Tk.W + Tk.S) # Add Scrollbar xscr = Tk.Scrollbar(self.image_frame, orient=Tk.HORIZONTAL, command=self.canvas.xview) xscr.grid(row=1, column=0, sticky=Tk.E + Tk.W) yscr = Tk.Scrollbar(self.image_frame, orient=Tk.VERTICAL, command=self.canvas.yview) yscr.grid(row=0, column=1, sticky=(Tk.N, Tk.S)) self.canvas.config(xscrollcommand=xscr.set, yscrollcommand=yscr.set) self.canvas.create_image(0, 0, image=self.image, anchor=Tk.NW) def redraw_canvas(self, file_name): self.image = ImageTk.PhotoImage(file=file_name) self.canvas.config(scrollregion=(0, 0, self.image.width(), self.image.height())) self.canvas.create_image(0, 0, image=self.image, anchor=Tk.NW) def redraw_diag_image(self, event=None): source = intern(self.text.get("1.0", Tk.END).encode("utf-8")) if source is not self.source: self.diag_method(source, self.tmp.name, self.image_format) if getsize(self.tmp.name) > 0: self.redraw_canvas(self.tmp.name) self.source = source def open_permanent_link(self): url = self.make_permanent_link() webbrowser.open_new_tab(url) def make_permanent_link(self): import base64 source = intern(self.text.get("1.0", Tk.END).encode("utf-8")) url = _DIAG_LINK_PREFIX + base64.urlsafe_b64encode(source) print url return url def quit(self): self.tmp.close() self.root.destroy()
class ClientGUI(object): def __init__(self, windowTitle="Client GUI"): # create new instance of TK self.base_gui = pygui.Tk() # store the windowTitle in an object attribute self.base_window_title = windowTitle # Connection Details self.connection_host = '' self.connection_name = '' self.connection_port = 0 # Client Object self.client = None # [Connection GUI Initialization] ::start self.connection_gui_bootstrapped = False self.connection_config_frame = pygui.Frame(self.base_gui) self.host_to_use_field = pygui.Entry(self.connection_config_frame) self.port_to_use_field = pygui.Entry(self.connection_config_frame) self.name_field = pygui.Entry(self.connection_config_frame) self.connect_server_btn = pygui.Button(self.connection_config_frame, text="Connect", command=self.connect_to_server) # [Connection GUI Initialization] ::end # [Main GUI Initialization] ::start self.main_gui_bootstrapped = False self.chat_room_frame = pygui.Frame(self.base_gui) self.activity_log_area = ScrolledText(self.chat_room_frame, height=10, width=50) self.message_field = pygui.Entry(self.chat_room_frame) self.submit_msg_btn = pygui.Button(self.chat_room_frame, text="Send", command=self.send_msg) self.exit_chat_btn = pygui.Button(self.chat_room_frame, text="Leave Chat Room", command=lambda: self.switch_context('connection')) # [Connection GUI Initialization] ::end def bootstrap(self): if self.client is None: print "Client Object must be specified. Call the set_client() method and set the ClientGUI Object." sys.exit(1) self.connection_gui() # set window title self.base_gui.wm_title(self.base_window_title) # handle close button self.base_gui.protocol("WM_DELETE_WINDOW", self.destroy_gui) # Start the GUI self.base_gui.mainloop() def connection_gui(self): # [Config Section] :start # assemble the UI and the frame if the attribute does not exist if self.connection_gui_bootstrapped is False: # Add field for host/hostname to use pygui.Label(self.connection_config_frame, text="Host").grid(row=0, column=0) self.host_to_use_field.grid(row=0, column=1) # Add field for port to use pygui.Label(self.connection_config_frame, text="Port").grid(row=1, column=0) self.port_to_use_field.grid(row=1, column=1) # Add field for chat username/alias pygui.Label(self.connection_config_frame, text="Name").grid(row=2, column=0) self.name_field.grid(row=2, column=1) self.connect_server_btn.grid(row=3, column=1) self.connection_gui_bootstrapped = True self.connection_config_frame.pack(side=pygui.TOP, padx=10, pady=10) # [Config Section] :end def main_gui(self): # [Chat Room] ::start # assemble the UI and the frame if the attribute does not exist if self.main_gui_bootstrapped is False: self.activity_log_area.grid(row=0) self.activity_log_area.edit_modified(0) self.activity_log_area.config(highlightbackground="black") self.activity_log_area.bind('<<Modified>>', self.scroll_to_end) self.message_field.grid(row=1, column=0) self.message_field.config(width=30) self.message_field.bind("<Return>", self.send_msg) self.submit_msg_btn.grid(row=1, column=1) self.exit_chat_btn.grid(row=2) self.main_gui_bootstrapped = True # empty the chat logs self.activity_log_area.delete("1.0", pygui.END) # show the frame for chat room self.chat_room_frame.pack(side=pygui.TOP, padx=10, pady=10) # [Chat Room] ::end def destroy_gui(self): # disconnect from the server self.client.disconnect() # destroy the window self.base_gui.destroy() def switch_context(self, context): if context == 'main': # hide the connection frame/GUI from the window if hasattr(self, 'connection_config_frame'): self.connection_config_frame.pack_forget() self.main_gui() title = "%s connected on %s:%s - %s" % (strip_uid(self.connection_name), self.connection_host, str(self.connection_port), self.base_window_title) # change the window title to show the connection details self.base_gui.wm_title(title) else: # disconnect from the server self.client.disconnect() # hide the chat room frame/GUI from the window if hasattr(self, 'chat_room_frame'): self.chat_room_frame.pack_forget() self.connection_gui() # set window title self.base_gui.wm_title(self.base_window_title) def scroll_to_end(self, *_): # scroll to the end of text area self.activity_log_area.see(pygui.END) self.activity_log_area.edit_modified(0) def connect_to_server(self): hostval = self.host_to_use_field.get() portval = self.port_to_use_field.get() nameval = self.name_field.get() if hostval != '' and portval != '' and nameval != '': self.connection_host = str(hostval) self.connection_name = str(nameval) # check if the host supplied is a valid ip address if not is_ipv4(self.connection_host): msgBox.showinfo("Client GUI", "Invalid IP Address") return # check if the input for port number is a valid integer try: self.connection_port = int(portval) except ValueError: msgBox.showinfo("Client GUI", "Invalid Port Number") return # initiate client-server connection if self.client.connect(self.connection_host, self.connection_port, self.connection_name) is True: # swap UI components/widgets self.switch_context('main') # log any broadcast message and disconnect on lost connection self.client.start_communications(self.log, lambda: self.switch_context('connection')) else: msgBox.showinfo("Client GUI", "Cant connect to server. Please try again later.") else: msgBox.showinfo("Client GUI", "Please enter the host, and port to connect to as well as your chat name") def set_client(self, client): self.client = client def send_msg(self, *_): message = self.message_field.get() # only send messages which are not empty if message: # show the message on your side self.log('[' + strip_uid(self.connection_name) + '] ' + message) # send the message to the other side self.client.send_msg(str(message)) # delete the message self.message_field.delete(0, pygui.END) def log(self, message): self.activity_log_area.insert(pygui.END, message + "\n")
class client_GUI(Thread): alias = None room = None flag = False in_room = False client = socket() IP = raw_input("IP Address: ") if not IP: IP = 'localhost' try: client.connect((IP, 9000)) except Exception as e: print "Could not connect to IP" logging.exception(e) exit() def __init__(self, master): Thread.__init__(self) frame = Frame(master) frame.pack() self.setAlias() #creates the thread for listening to the Server def run(self): Recieve(self.client) def clearWindow(self): for widget in root.winfo_children(): widget.destroy() def assemble_packet(self, msg, code): parser = Parser() if code == utils.codes["send_msg"]: date = datetime.datetime.now().strftime(utils.DATE_FORMAT) packet = parser.assemble(utils.codes["send_msg"], self.alias, self.room, date, msg) elif code == utils.codes["set_alias"]: packet = parser.assemble(utils.codes["set_alias"], msg, "", "", "") elif code == utils.codes["set_room"]: packet = parser.assemble(utils.codes["set_room"], self.alias, msg, "", "") elif code == utils.codes["get_roomlist"]: packet = parser.assemble(utils.codes["get_roomlist"], self.alias, self.room, "", "") logging.info("Sending packet %s" % (packet)) return packet def breakdown_packet(self, packet): parser = Parser() parser.breakdown(packet) if parser.code == utils.codes["recv_msg"]: return parser.body elif parser.code == utils.codes["recv_roomlist"]: return parser.body elif parser.code == utils.codes["alias_success"]: self.alias = parser.alias return parser.body elif parser.code == utils.codes["alias_invalid"]: return parser.alias elif parser.code == utils.codes["room_success"]: self.room = parser.room return parser.room elif parser.code == utils.codes["room_invalid"]: return parser.room else: logging.info("Invalid packet recieved") return def setAlias(self): def setRoom(): aliasCheck = None self.alias = self.aliasInfo.get().translate(None, '\\') self.alias = self.alias.translate(None, ' ') if len(self.alias) > 20: self.alias = self.alias[:19] packet = self.assemble_packet(self.alias, utils.codes["set_alias"]) try: self.client.send(packet) except Exception as e: logging.exception(e) time.sleep(1) if not inputQueue.empty(): aliasCheck = str(inputQueue.get()) if aliasCheck.startswith(utils.codes["alias_success"]): roomList = self.breakdown_packet(aliasCheck) self.clearWindow() self.changeRoom(roomList) else: self.flag = True self.clearWindow() self.setAlias() else: self.flag = True self.clearWindow() self.setAlias() self.intro = Label(root, text="Welcome to TrashTalk", width=600, font=8000, fg="red", pady=100) self.intro.pack(anchor=CENTER) self.aliasLabel = Label(root, text="Set Your Alias:", pady=10) self.aliasLabel.pack(anchor=CENTER) self.aliasInfo = Entry(root, width=40) self.aliasInfo.pack(anchor=CENTER) self.spacing = Label(root, text="", pady=70) if self.flag: self.spacing.config(text="Invalid, please try again", fg="red") self.spacing.pack(anchor=CENTER) self.login = Button(root, height=2, width=10, text="Pick A Room", command=setRoom) self.login.pack(anchor=CENTER) def changeRoom(self, roomList): def enterRoom(): self.clearWindow() chosenRoom = self.v.get() if not chosenRoom: chosenRoom = firstRoom packet = self.assemble_packet(chosenRoom, utils.codes["set_room"]) try: self.client.send(packet) except Exception as e: logging.exception(e) time.sleep(1) if not inputQueue.empty(): roomCheck = str(inputQueue.get()) if roomCheck.startswith(utils.codes["room_success"]): self.room = chosenRoom self.in_room = True self.inRoom(chosenRoom) else: self.changeRoom(roomList) root.title("TrashTalk") rooms = roomList.split() firstRoom = rooms[0] self.v = StringVar(value=firstRoom) self.roomLabel = Label( root, text="Select which Chat Room You Would Like to Join", pady=70, font=800) self.roomLabel.pack(anchor=CENTER) for room in rooms: self.b = Radiobutton(root, text=room, variable=self.v, value=room) self.b.pack(anchor=CENTER) self.b.deselect() self.login = Button(root, height=2, width=20, text="Enter Chosen Room", command=enterRoom) self.login.place(relx=0.5, y=400, anchor=CENTER) def inRoom(self, room): def newMessage(): message = self.entryBox.get() if message: self.entryBox.delete(0, 'end') message = message.translate(None, '\\') if len(message) > 900: message = message[:899] packet = self.assemble_packet(message, utils.codes["send_msg"]) try: self.client.send(packet) except Exception as e: logging.exception(e) def changingRoom(): packet = self.assemble_packet("", utils.codes["get_roomlist"]) try: self.client.send(packet) except Exception as e: logging.exception(e) time.sleep(1) if not inputQueue.empty(): roomCheck = str(inputQueue.get()) if roomCheck.startswith(utils.codes["recv_roomlist"]): in_room = False roomList = self.breakdown_packet(roomCheck) self.clearWindow() self.changeRoom(roomList) def exitProgram(): self.client.close() os._exit(1) root.title("TrashTalk - " + room) self.messageHistory = ScrolledText(root, undo=True) self.messageHistory.bind("<Key>", lambda e: "break") self.messageHistory.pack(anchor=W) self.messageHistory.insert( END, "Welcome " + self.alias + " to the " + room + " chat room!") self.entryBox = Entry(root, width=85) self.entryBox.place(x=0, y=400, anchor=W) self.sendButton = Button(root, height=2, width=19, text="Send Message", command=newMessage) self.sendButton.place(x=518, y=388, anchor=NW) self.sendButton = Button(root, height=4, width=25, text="Change Room", command=changingRoom) self.sendButton.place(x=725, y=300, anchor=NW) self.sendButton = Button(root, height=4, width=25, text="Quit", command=exitProgram) self.sendButton.place(x=725, y=400, anchor=NW) def update_chat(): if not buildQueue.empty(): MYINFO = buildQueue.get() if MYINFO.startswith(utils.codes["leave_room"]): changingRoom() elif self.in_room: msg = self.breakdown_packet(MYINFO) endOfBox = self.messageHistory.vbar.get() self.messageHistory.insert(END, "\n" + msg) if endOfBox[1] == 1.0: endOfBox = self.messageHistory.see("end") root.after(100, update_chat) root.after(100, update_chat)
def producer(id): for i in range(5): time.sleep(0.1) print('put') dataQueue.put('[producer id=%d, count=%d]' % (id, i)) def consumer(root): while not dataQueue.empty(): data = dataQueue.get(block=False) root.insert('end', 'consumer got => %s\n' % str(data)) root.see('end') root.after(250, lambda: consumer(root)) # 4 times per sec def makethreads(): for i in range(4): thread.start_new_thread(producer, (i, )) if __name__ == '__main__': # main GUI thread: spawn batch of worker threads on each mouse click from ScrolledText import ScrolledText root = ScrolledText() root.pack() root.bind('<Button-1>', lambda event: makethreads()) consumer(root) # start queue check loop in main thread root.mainloop() # pop-up window, enter tk event loop
class Tkui(base.BaseUI): """ This is a ui class which handles the complete Tk user interface. """ def __init__(self): """ Initializes.""" base.BaseUI.__init__(self) # internal ui queue self._event_queue = Queue.Queue() # map of session -> (bold, foreground, background) self._currcolors = {} # ses -> string self._unfinishedcolor = {} self._viewhistory = 0 self._do_i_echo = 1 # holds a map of window names -> window references self._windows = {} # instantiate all the widgets self._tk = Tk() self._tk.geometry("800x600") self.settitle() if os.name == "posix": fnt = tkFont.Font(family="Courier", size=12) else: fnt = tkFont.Font(family="Fixedsys", size=12) self._entry = CommandEntry( self._tk, self, fg="white", bg="black", insertbackground="yellow", font=fnt, insertwidth="2" ) self._entry.pack(side="bottom", fill="both") self._topframe = Frame(self._tk) self._topframe.pack(side="top", fill="both", expand=1) self._txt = ScrolledText(self._topframe, fg="white", bg="black", font=fnt, height=20) self._txt.pack(side="bottom", fill="both", expand=1) self._txt.bind("<KeyPress>", self._ignoreThis) self._txtbuffer = ScrolledText(self._topframe, fg="white", bg="black", font=fnt, height=20) self._txtbuffer.bind("<KeyPress-Escape>", self.escape) self._txtbuffer.bind("<KeyPress>", self._ignoreThis) self._entry.focus_set() self._initColorTags() self.dequeue() exported.hook_register("config_change_hook", self.configChangeHandler) exported.hook_register("to_user_hook", self.write) # FIXME - fix this explanation. this is just terrible. tc = config.BoolConfig( "saveinputhighlight", 0, 1, "Allows you to change the behavior of the command entry. When " "saveinputhighlight is off, we discard whatever is on the entry " "line. When it is on, we will retain the contents allowing you " "to press the enter key to do whatever you typed again.", ) exported.add_config("saveinputhighlight", tc) self._quit = 0 def runui(self): global HELP_TEXT exported.add_help("tkui", HELP_TEXT) exported.write_message('For tk help type "#help tkui".') exported.add_command("colorcheck", colorcheck_cmd) # run the tk mainloop here self._tk.mainloop() def wantMainThread(self): # The tkui needs the main thread of execution so we return # a 1 here. return 1 def quit(self): if not self._quit: self._quit = 1 self._topframe.quit() def dequeue(self): qsize = self._event_queue.qsize() if qsize > 10: qsize = 10 for i in range(qsize): ev = self._event_queue.get_nowait() ev.execute(self) self._tk.after(25, self.dequeue) def settitle(self, title=""): """ Sets the title bar to the Lyntin title plus the given string. @param title: the title to set @type title: string """ if title: title = constants.LYNTINTITLE + title else: title = constants.LYNTINTITLE self._event_queue.put(_TitleEvent(self._tk, title)) def removeWindow(self, windowname): """ This removes a NamedWindow from our list of NamedWindows. @param windowname: the name of the window to write to @type windowname: string """ if self._windows.has_key(windowname): del self._windows[windowname] def writeWindow(self, windowname, message): """ This writes to the window named "windowname". If the window does not exist, we spin one off. It handles ansi text and messages just like writing to the main window. @param windowname: the name of the window to write to @type windowname: string @param message: the message to write to the window @type message: string or Message instance """ self._event_queue.put(_WriteWindowEvent(windowname, message)) def writeWindow_internal(self, windowname, message): if not self._windows.has_key(windowname): self._windows[windowname] = NamedWindow(windowname, self, self._tk) self._windows[windowname].write(message) def _ignoreThis(self, tkevent): """ This catches keypresses from the history buffer.""" # kludge so that ctrl-c doesn't get caught allowing windows # users to copy the buffer.... if tkevent.keycode == 17 or tkevent.keycode == 67: return self._entry.focus() if tkevent.char: # we do this little song and dance so as to pass events # we don't want to deal with to the entry widget essentially # by creating a new event and tossing it in the event list. # it only sort of works--but it's the best code we've got # so far. args = ("event", "generate", self._entry, "<KeyPress>") args = args + ("-rootx", tkevent.x_root) args = args + ("-rooty", tkevent.y_root) args = args + ("-keycode", tkevent.keycode) args = args + ("-keysym", tkevent.keysym) self._tk.tk.call(args) return "break" def pageUp(self): """ Handles prior (Page-Up) events.""" if self._viewhistory == 0: self._txtbuffer.pack(side="top", fill="both", expand=1) self._viewhistory = 1 self._txtbuffer.delete("1.0", "end") lotofstuff = self._txt.get("1.0", "end") self._txtbuffer.insert("end", lotofstuff) for t in self._txt.tag_names(): taux = None tst = 0 for e in self._txt.tag_ranges(t): if tst == 0: taux = e tst = 1 else: tst = 0 self._txtbuffer.tag_add(t, str(taux), str(e)) self._txtbuffer.yview("moveto", "1") if os.name != "posix": self._txtbuffer.yview("scroll", "20", "units") self._tk.update_idletasks() self._txt.yview("moveto", "1.0") if os.name != "posix": self._txt.yview("scroll", "220", "units") else: # yscroll up stuff self._txtbuffer.yview("scroll", "-15", "units") def pageDown(self): """ Handles next (Page-Down) events.""" if self._viewhistory == 1: # yscroll down stuff self._txtbuffer.yview("scroll", "15", "units") def escape(self, tkevent): """ Handles escape (Escape) events.""" if self._viewhistory == 1: self._txtbuffer.forget() self._viewhistory = 0 else: self._entry.clearInput() def configChangeHandler(self, args): """ This handles config changes including mudecho. """ name = args["name"] newvalue = args["newvalue"] if name == "mudecho": if newvalue == 1: # echo on self._do_i_echo = 1 self._entry.configure(show="") else: # echo off self._do_i_echo = 0 self._entry.configure(show="*") def _yadjust(self): """Handles y scrolling after text insertion.""" self._txt.yview("moveto", "1") # if os.name != 'posix': self._txt.yview("scroll", "20", "units") def _clipText(self): """ Scrolls the text buffer up so that the new text written at the bottom of the text buffer can be seen. """ temp = self._txt.index("end") ind = temp.find(".") temp = temp[:ind] if temp.isdigit() and int(temp) > 800: self._txt.delete("1.0", "100.end") def write(self, args): """ This writes text to the text buffer for viewing by the user. This is overridden from the 'base.BaseUI'. """ self._event_queue.put(_OutputEvent(args)) def write_internal(self, args): mess = args["message"] if type(mess) == types.StringType: mess = message.Message(mess, message.LTDATA) line = mess.data ses = mess.session if line == "" or self.showTextForSession(ses) == 0: return color, leftover = buffer_write(mess, self._txt, self._currcolors, self._unfinishedcolor) if mess.type == message.MUDDATA: self._unfinishedcolor[ses] = leftover self._currcolors[ses] = color self._clipText() self._yadjust() def convertColor(self, name): """ Tk has this really weird color palatte. So I switched to using color names in most cases and rgb values in cases where I couldn't find a good color name. This method allows me to specify either an rgb or a color name and it converts the color names to rgb. @param name: either an rgb value or a name @type name: string @returns: the rgb color value @rtype: string """ if name.startswith("#"): return name rgb = self._tk._getints(self._tk.tk.call("winfo", "rgb", self._txt, name)) rgb = "#%02x%02x%02x" % (rgb[0] / 256, rgb[1] / 256, rgb[2] / 256) print name, "converted to: ", rgb return rgb def _initColorTags(self): """ Sets up Tk tags for the text widget (fg/bg/u).""" for ck in fg_color_codes.keys(): color = self.convertColor(fg_color_codes[ck]) self._txt.tag_config(ck, foreground=color) self._txtbuffer.tag_config(ck, foreground=color) for ck in bg_color_codes.keys(): self._txt.tag_config(ck, background=bg_color_codes[ck]) self._txtbuffer.tag_config(ck, background=bg_color_codes[ck]) self._txt.tag_config("u", underline=1) self._txtbuffer.tag_config("u", underline=1) def colorCheck(self): """ Goes through and displays all the combinations of fg and bg with the text string involved. Purely for debugging purposes. """ fgkeys = ["30", "31", "32", "33", "34", "35", "36", "37"] bgkeys = ["40", "41", "42", "43", "44", "45", "46", "47"] self._txt.insert("end", "color check:\n") for bg in bgkeys: for fg in fgkeys: self._txt.insert("end", str(fg), (fg, bg)) self._txt.insert("end", str("b" + fg), ("b" + fg, bg)) self._txt.insert("end", "\n") for fg in fgkeys: self._txt.insert("end", str(fg), (fg, "b" + bg)) self._txt.insert("end", str("b" + fg), ("b" + fg, "b" + bg)) self._txt.insert("end", "\n") self._txt.insert("end", "\n") self._txt.insert("end", "\n")
lines= str(len(raw.split("\n"))) chars=str(len(raw.replace("\n",""))) raw = raw.translate(string.maketrans("",""), string.punctuation) a= str(" ".join(raw.split())) if chars=="0" and lines == "1": wordcount.set("0 Words 0 Lines 0 Characters") else: b=a.split(" ") if b[0]=="": wordcount.set("0 Words "+lines+ " Lines "+chars+" Characters") else: wordcount.set(str(len(b))+" Words "+lines+ " Lines "+chars+" Characters") master.after(100,autoupdate) wordcount=StringVar() textbox = ScrolledText(master) textbox.pack() textbox.focus_set() textbox.event_generate('<<Paste>>') textbox.bind('<Control-a>', highlightall) textbox.bind('<Control-A>', highlightall) words=Label(master,textvariable=wordcount) words.pack(side=BOTTOM,padx=20) autoupdate() mainloop()
def compile_code(self, event=None): if not hasattr(self.editwin.io, 'filename') or self.editwin.io.filename is None: return filename = self.editwin.io.filename try: f = self.editwin.ftype.get() except: return if f in ('C/l',): compiler = 'gcc' command = idleConf.GetOption('extensions', 'CompileCode', 'compile_c') elif f in ('C++/l',): compiler = 'g++' command = idleConf.GetOption('extensions', 'CompileCode', 'compile_cpp') else: return def close_(w, event=None): w.grab_release() w.withdraw() raw_name = os.path.splitext(filename)[0] exe_name = raw_name+'.exe' basename = os.path.basename(filename) args = command.format(raw_name) sub_win = Toplevel(self.text) sub_win.title('In compilation') ce = ScrolledText( sub_win, width=80, height=24, fg='#b7b7b7', bg='black', font='Consolas 10', insertbackground='white', ) ce.bind('<Escape>', lambda event: close_(sub_win, event)) ce.pack(fill='both', expand=True) ce.focus_set() def compile_(): sp = subprocess.Popen( args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, ) self.compile_failed = compile_failed = sp.wait() compile_message = sp.communicate()[1] compile_message = re.sub( r'^{}:'.format(filename.replace('\\', r'\\')), basename+':', compile_message, flags=re.M, ) self.compile_message = compile_message if not compile_message: return if compile_failed: title = 'Compilation failed' else: title = 'Compilation succeeded (with warning)' sub_win.title(title) ## ce.insert('1.0', compile_message) ## ce.focus_set() d = threading.Thread(name='comp', target=compile_) d.start() d.join(6) if d.is_alive(): p = subprocess.Popen( 'taskkill /im {} /f /t'.format(compiler), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, ) stdout, stderr = p.communicate() if not self.compile_message: close_(sub_win, None) tkMessageBox.showinfo( parent=self.text, title=compiler, message='Compilation succeeded.', ) else: ce.insert('end', self.compile_message) ce.focus_set()
class GUI_hcheck: # do everything! def __init__(self): self.top = Tk() self.top.title('Health Check Tool') self.top.geometry('1400x800') #------- Label,Entry defination ----------# self.l1 = Label(self.top, text="IP:").grid(row=1, column=1, sticky="w") self.e1 = Entry(self.top) self.e1.grid(row=1, column=2,sticky="ew") self.l2 = Label(self.top, text="User:"******"w") self.e2 = Entry(self.top) self.e2.grid(row=2, column=2,sticky="ew") self.l3 = Label(self.top, text="Passwd:").grid(row=3, column=1, sticky="w") self.e3 = Entry(self.top) self.e3['show'] = '*' self.e3.grid(row=3, column=2,sticky="ew") self.l4 = Label(self.top, text="Command pool:").grid(row=4, column=1, sticky="e") self.l5 = Label(self.top, text="To be run command:").grid(row=4, column=5, sticky="e") self.e4 = Entry(self.top, width=30) self.e4.grid(row=16, column=0, columnspan=3, sticky="ew") #------- Checkbutton defination ----------# self.cb1State = IntVar() self.cb1 = Checkbutton(self.top, variable=self.cb1State, text = "Always Yes", command=self.callCheckbutton) self.cb1.grid(row=21, column=16) #------- Listbox defination ----------# self.cmdfm = Frame(self.top) self.cmdsb = Scrollbar(self.cmdfm) self.cmdsb_x = Scrollbar(self.cmdfm,orient = HORIZONTAL) self.cmdsb.pack(side=RIGHT, fill=Y) self.cmdsb_x.pack(side=BOTTOM, fill=X) self.cmdls = Listbox(self.cmdfm, selectmode=EXTENDED, height=25, width=40, xscrollcommand=self.cmdsb_x.set, yscrollcommand=self.cmdsb.set) self.cmdsb.config(command=self.cmdls.yview) self.cmdsb_x.config(command=self.cmdls.xview) self.cmdls.pack(side=LEFT, fill=BOTH) self.cmdfm.grid(row=5, rowspan=10, column=0,columnspan=4,sticky="ew") self.db_file = os.path.join(os.getcwd(),'%s' % constants.DB_NAME) flist = utility.load_file(self.db_file) if flist != None: log.debug ("db file found, start load command") for element in flist: element = element.strip('\n') if element == '' or element.startswith('#'): continue self.cmdls.insert(END, element) else: log.debug ("db file doesn't existed, initail cmd") for element in constants.CMD_LIST_COMM: self.cmdls.insert(END, element) self.dirfm = Frame(self.top) self.dirsb = Scrollbar(self.dirfm) self.dirsb_x = Scrollbar(self.dirfm,orient = HORIZONTAL) self.dirsb.pack(side=RIGHT, fill=Y) self.dirsb_x.pack(side=BOTTOM, fill=X) self.dirs = Listbox(self.dirfm, selectmode=EXTENDED, height=25, width=40, xscrollcommand=self.dirsb_x.set,yscrollcommand=self.dirsb.set) self.dirsb.config(command=self.dirs.yview) self.dirsb_x.config(command=self.dirs.xview) self.dirs.pack(side=LEFT, fill=BOTH) self.dirfm.grid(row=5, rowspan=10, column=5,columnspan=4,sticky="ew") #------- Buttion defination ----------# # add command button self.b1 = Button(self.top,text=">>",width=6,borderwidth=3,relief=RAISED, command=self.move_cmd) self.b1.grid(row=7, column=4) # del command button self.b2 = Button(self.top,text="<<",width=6,borderwidth=3,relief=RAISED, command=self.del_cmd) self.b2.grid(row=8, column=4) # move up command button self.b3 = Button(self.top,text="up",width=6,borderwidth=3,relief=RAISED, command=self.up_cmd) self.b3.grid(row=7, column=10) # move down command button self.b4 = Button(self.top,text="down",width=6,borderwidth=3,relief=RAISED, command=self.down_cmd) self.b4.grid(row=8, column=10) # start command button self.b5 = Button(self.top,text="Start",bg='red',width=10,borderwidth=3,relief=RAISED, command=self.start_process) self.b5.grid(row=2, column=11) # yes button self.b6 = Button(self.top,text="Yes",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_yes) self.b6.grid(row=21, column=13) # No button self.b7 = Button(self.top,text="No",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_no) self.b7.grid(row=21, column=14) # Skip button self.b8 = Button(self.top,text="Skip",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_skip) self.b8.grid(row=21, column=15) # Add button self.b9 = Button(self.top,text="add cmd",width=10,borderwidth=3,relief=RAISED, command=self.add_command) self.b9.grid(row=15, column=1) # Del button self.b10 = Button(self.top,text="del cmd",width=10,borderwidth=3,relief=RAISED, command=self.del_command) self.b10.grid(row=15, column=2) # Manual button self.manual = False self.b11 = Button(self.top,text="Manual model",width=10,borderwidth=3,relief=RAISED, command=self.manual_mode) self.b11.grid(row=2, column=12) #------- ScrolledText defination ----------# self.sfm = Frame(self.top) self.console = ScrolledText(self.sfm,height=45, width=86,bg='black',fg='green',insertbackground='green') self.console['font'] = ('lucida console','10') self.console.bind("<Return>", self.process_input) self.console.pack() self.sfm.grid(row=4, rowspan=15, column=11,columnspan=10,sticky="ew") self.redir = redirect(self.console) sys.stdout = self.redir sys.stderr = self.redir self.fconsole = logging.StreamHandler(sys.stdout) self.fconsole.setLevel(logging.INFO) logging.getLogger('').addHandler(self.fconsole) #------- Menu defination ----------# self.menubar = Menu() # file menu self.fmenu = Menu() #self.fmenu.add_command(label = 'New',command=self.new_win) self.fmenu.add_command(label = 'Import cmd',command=self.load_cmd) self.fmenu.add_command(label = 'Export cmd',command=self.export_cmd) self.menubar.add_cascade(label = 'File', menu = self.fmenu) # edit menu self.emenu = Menu() self.cmenu = Menu() self.cvar = StringVar() for item in ['white/black', 'black/white', 'green/black']: self.cmenu.add_radiobutton(label = item, variable=self.cvar, value=item, command=self.sel_color_style) self.emenu.add_cascade(label = 'console style', menu = self.cmenu) self.emenu.add_command(label = 'reset cmd pool',command=self.reset_cmd_pool) self.menubar.add_cascade(label = 'Edit', menu = self.emenu) self.top['menu'] = self.menubar def new_win(self): #GUI_hcheck() pass def sel_color_style(self): log.debug ("select console color style: %s " % self.cvar.get()) color = self.cvar.get() if color == 'white/black': self.console.config(bg='black',fg='white',insertbackground='white') elif color == 'black/white': self.console.config(bg='white',fg='black',insertbackground='black') elif color == 'green/black': self.console.config(bg='black',fg='green',insertbackground='green') def move_cmd(self): if self.cmdls.curselection() != (): for i in self.cmdls.curselection(): if utility.elemet_exists(self.dirs.get(0,END), self.cmdls.get(i)) == None: self.dirs.insert(END,self.cmdls.get(i)) log.debug ("move command %s" % self.cmdls.get(i)) else: tkMessageBox.showwarning('Message', 'Please select at lease one item') def load_cmd(self): file = tkFileDialog.askopenfilename() flist = utility.load_file(file) if flist != None: self.dirs.delete(0,END) for element in flist: element = element.strip('\n') if element == '' or element.startswith('#'): continue if utility.elemet_exists(self.dirs.get(0,END), element) == None: self.dirs.insert(END, element) else: tkMessageBox.showerror('Message', 'import failed') def export_cmd(self): file = tkFileDialog.askopenfilename() if utility.export_file(self.dirs.get(0,END), file) == True: tkMessageBox.showinfo('Message', 'export finish') else: tkMessageBox.showerror('Message', 'export failed') def del_cmd(self): if self.dirs.curselection() != (): for i in self.dirs.curselection(): self.dirs.delete(i) else: tkMessageBox.showwarning('Message', 'Please select at lease one item') def up_cmd(self): select = self.dirs.curselection() if (len(select)) >= 2: tkMessageBox.showwarning('Message', 'Only one select is supported') return log.debug ("move up select pos: %s" % str(select)) if select != () and select != (0,): element = self.dirs.get(select) self.dirs.delete(select) self.dirs.insert((select[0] - 1), element) self.dirs.select_set(select[0] - 1) def down_cmd(self): select = self.dirs.curselection() if (len(select)) >= 2: tkMessageBox.showwarning('Message', 'Only one select is supported') return log.debug ("move down select pos: %s" % str(select)) if select != () and select != (END,): element = self.dirs.get(select) self.dirs.delete(select) self.dirs.insert((select[0] + 1), element) self.dirs.select_set(select[0] + 1) def start_process(self): log.debug ("current thread total numbers: %d" % threading.activeCount()) response = tkMessageBox.askokcancel('Message', 'Will start healthcheck, please click OK to continue, or cancel') if response == False: return th = threading.Thread(target=self.start_cmd) th.setDaemon(True) th.start() def start_cmd(self): self.manual = False cmd = list(self.dirs.get(0,END)) if len(cmd) == 0: log.info ("To be run cmd numbers none, quit...") return log.debug ("fetch cmd list from GUI: %s" % cmd) (ip, port) = utility.getipinfo(self.e1.get()) log.debug ("get ip infor-> ip: %s, port:%s" % (ip,port)) if ip == False: log.error ("Given ip infor is wrong! The right ip address: xxx.xxx.xxx.xxx or IP:port ") return self.b5.config(state=DISABLED) self.b11.config(state=DISABLED) self.console.delete('1.0',END) try: self.wf = Workflow(cmd, ip, self.e2.get(), self.e3.get(), port) self.wf.start() except: pass self.b5.config(state=NORMAL) self.b11.config(state=NORMAL) def manual_mode(self): cmd = [] (ip, port) = utility.getipinfo(self.e1.get()) log.debug ("get ip infor-> ip: %s, port:%s" % (ip,port)) if ip == False: log.error ("Given ip infor is wrong! The right ip address: xxx.xxx.xxx.xxx or IP:port ") return self.wf_manual = Workflow(cmd, ip, self.e2.get(), self.e3.get(), port) if self.wf_manual.setup_ssh(self.wf_manual.hostip) == False: log.error ("\nssh setup error! please check ip/user/passwd and network is okay") del self.wf_manual return self.console.delete('1.0',END) self.console.insert(END, "Switch to manual mode...\n\ Please input command directly after \">>> \"\n\n") self.prompt = ">>> " self.insert_prompt() self.manual = True self.b5.config(state=DISABLED) self.b11.config(state=DISABLED) def set_confirm_yes(self): try: self.wf.set_confirm('Yes') except AttributeError: log.debug("wf doesn't existed") def set_confirm_no(self): try: self.wf.set_confirm('No') except AttributeError: log.debug("wf doesn't existed") def set_confirm_skip(self): try: self.wf.set_confirm('Skip') except AttributeError: log.debug("wf doesn't existed") def callCheckbutton(self): try: if self.cb1State.get() == 1: self.wf.set_automatic(5) else: self.wf.set_automatic(None) except AttributeError: log.debug("wf doesn't existed") self.cb1.deselect() tkMessageBox.showwarning('Message', 'please press start button first') def saveinfo(self): pass def add_command(self): item = self.e4.get() if item != '': if utility.elemet_exists(self.cmdls.get(0,END), item) == None: self.cmdls.insert(END,item) self.cmdls.see(END) log.debug ("add new command %s" % item) self.save_command() else: tkMessageBox.showwarning('Message', 'entry can not empty') def del_command(self): if self.cmdls.curselection() != (): for i in self.cmdls.curselection(): self.cmdls.delete(i) self.save_command() else: tkMessageBox.showwarning('Message', 'Please select at lease one item') def save_command(self): if utility.export_file(self.cmdls.get(0,END), self.db_file) != True: log.error ("save command pool failed") def reset_cmd_pool(self): log.debug ("start to reset command pool list") self.cmdls.delete(0,END) for element in constants.CMD_LIST_COMM: self.cmdls.insert(END, element) self.save_command() def insert_prompt(self): c = self.console.get("end-2c") if c != "\n": self.console.insert("end", "\n") self.console.insert("end", self.prompt, ("prompt",)) #self.text.insert("end", self.prompt) # this mark lets us find the end of the prompt, and thus # the beggining of the user input self.console.mark_set("end-of-prompt", "end-1c") self.console.mark_gravity("end-of-prompt", "left") def process_input(self,event): index = self.console.index("end-1c linestart") line = self.console.get(index,'end-1c') log.debug ("last line: %s" % line) if self.manual == True: self.console.insert("end", "\n") command = self.console.get("end-of-prompt", "end-1c") command = command.strip() if command != '': if command == 'bye' or command == 'exit': log.info ("quit from manual mode...") self.wf_manual.ssh.close() self.manual = False self.b5.config(state=NORMAL) self.b11.config(state=NORMAL) return elif command == 'help': log.info ("This is used for run command on target server by ssh, for example: >>> df -h, >>> svcs -xv") elif self.wf_manual.remote_cmd(command) == 1: log.error ("command %s execute failed" % command) self.insert_prompt() self.console.see("end") # this prevents the class binding from firing, since we # inserted the newline in this method return "break" else: if line == 'Yes' or line == 'y' or line == 'yes': self.set_confirm_yes() elif line == 'No' or line == 'n' or line == 'no': self.set_confirm_no() elif line == 'Skip' or line == 's' or line == 'skip': self.set_confirm_skip() else: pass
class ServerGUI(object): server_on = False def __init__(self, window_title="Server GUI"): self.base_gui = pygui.Tk() self.window_title = window_title self.server_port = 0 self.server = None # [GUI Initialization] ::start self.server_config_frame = pygui.Frame(self.base_gui) self.port_to_use_field = pygui.Entry(self.server_config_frame) self.server_controls_frame = pygui.Frame(self.base_gui) self.create_server_btn = pygui.Button(self.server_controls_frame, text="Start Server", command=self.invoke_server) self.stop_server_btn = pygui.Button(self.server_controls_frame, text="Stop Server", command=self.stop_server) self.quit_btn = pygui.Button(self.server_controls_frame, text="Quit", command=self.destroy_gui) # [GUI Initialization] ::end self.server_logs_frame = pygui.Frame(self.base_gui) self.activity_log_area = ScrolledText(self.server_logs_frame, height=10, width=50) def bootstrap(self): if self.server is None: print "Server Object must be specified. Call the set_server() method and set the ServerGUI Object." sys.exit(1) # set window title self.base_gui.wm_title(self.window_title) # [Config Section] :start self.server_config_frame.pack(side=pygui.TOP, pady=10) # Add field for port to use pygui.Label(self.server_config_frame, text="Server port to use").grid(row=0, column=0) self.port_to_use_field.grid(row=0, column=1) self.port_to_use_field.bind("<Return>", self.invoke_server) # [Config Section] :end # [Controls Section] ::start self.server_controls_frame.pack(side=pygui.RIGHT, fill=pygui.Y) # Add Start server button self.create_server_btn.grid(row=0, column=1) # Stop Server self.stop_server_btn.grid(row=1, column=1) # Quit Button self.quit_btn.grid(row=2, column=1) # [Controls Section] ::end # [Logs Section] ::start self.server_logs_frame.pack(side=pygui.LEFT, padx=10, pady=10) # Create a text area for showing logs. pygui.Label(self.server_logs_frame, text="Logs").grid(row=0) self.activity_log_area.edit_modified(0) self.activity_log_area.grid(row=1) self.activity_log_area.config(highlightbackground="black") self.activity_log_area.bind('<<Modified>>', self.scroll_to_end) # [Logs Section] ::end # handle close button self.base_gui.protocol("WM_DELETE_WINDOW", self.destroy_gui) # Start the GUI self.base_gui.mainloop() def set_server(self, server): self.server = server def scroll_to_end(self, *_): # scroll to the end of text area self.activity_log_area.see(pygui.END) self.activity_log_area.edit_modified(0) def destroy_gui(self): self.stop_server() self.base_gui.destroy() def stop_server(self, *_): if self.server_on is True: self.server.stop(self.log) # set the SERVER_ON flag to false to enable create a new server instance self.server_on = False else: self.log("Server already stopped.") def invoke_server(self, *_): portval = self.port_to_use_field.get() if portval != '': # check if the input for port number is a valid integer try: self.server_port = int(portval) except ValueError: msgBox.showinfo("Client GUI", "Invalid Port Number") return # start the server if not yet started if self.server_on is False: # log the message self.server.set_port(self.server_port) if not self.server.invoke(self.log): msgBox.showinfo( "Client GUI", "Cannot bind to port: %s. Please select another port to bind on." % str(self.server_port)) return # Prevent starting another instance of server self.server_on = True else: self.log("Server already started on port: " + str(self.server_port)) else: self.log( "Please provide port number for the server to bind on. Thanks!" ) def log(self, message): self.activity_log_area.insert(pygui.END, message + "\n")
class ViewportCard(object): """ Manages the graphical representation of a card in a Tkinter canvas. Creates and destroys items as necessary, facilitates editing, and so on and so forth. Members: * card: model.Card * viewport: GPViewport * gpfile: gpfile.GraphPaperFile, contains model.graph() * canvas: TKinter canvas we get drawn on * editing: bool, text is being edited * moving: bool, being dragged * moving_edgescroll_id: callback id to scroll periodically when hovering near edge of screen * resize_state: {} * resize_edgescroll_id: as moving_edgescroll_id * slot: calls callbacks whenever geometry changes * new_edge: if an edge is being dragged out from a handle, this is it. * card_after_new_edge: bool, if we should make a new card when edge is dropped. """ def __init__(self, viewport, gpfile, card): self.card = card self.viewport = viewport self.gpfile = gpfile self.canvas = viewport.canvas self.draw() self.editing = False self.moving = False self.moving_edgescroll_id = None self.resize_state = None self.resize_edgescroll_id = None # slot triggered when geometry (pos/size) changes # fn args: (self, x, y, w, h) self.geom_slot = Slot() self.deletion_slot = Slot() self.new_edge = None def draw(self): self.frame_thickness = 5 self.window = ResizableCanvasFrame( self.canvas, self.card.x, self.card.y, self.card.w, self.card.h, min_width=MIN_CARD_SIZE, min_height=MIN_CARD_SIZE, ) self.text = ScrolledText(self.window, wrap=WORD) self.text.pack(expand=1, fill="both") # set up text for editing, dragging, deleting self.text.bind("<Button-1>", self.mousedown) self.text.bind("<Shift-Button-1>", self.shiftmousedown) self.text.bind("<Double-Button-1>", self.doubleclick) self.text.bind("<B1-Motion>", self.mousemove) self.text.bind("<ButtonRelease-1>", self.mouseup) self.text.bind("<FocusIn>", self.focusin) self.text.bind("<FocusOut>", self.focusout) self.text.bind("<Control-Delete>", self.ctrldelete) self.text.insert(END, self.card.text) # set up frame for resizing self.window.bind("<Configure>", self.configure) self.window.save_callback = self.save_card # draw edge handles self.edge_handles = None # self.redraw_edge_handles() def redraw_edge_handles(self): """ Either creates or modifies the edge handles, little circles poking out the side of the card, based on the current position and width. self.edge_handles is a list of itemids of the circles in (top, right, bottom, left) order. """ def create_circle(bbox): # create circle suitable for edge-handle use new = self.canvas.create_oval(bbox[0], bbox[1], bbox[2], bbox[3], fill="green", outline="") self.canvas.addtag_withtag("card_handle_tag", new) # for z-ordering self.canvas.tag_bind(new, "<Button-1>", self.handle_click) self.canvas.tag_bind(new, "<Shift-Button-1>", self.handle_shift_click) self.canvas.tag_bind(new, "<B1-Motion>", self.handle_mousemove) self.canvas.tag_bind(new, "<ButtonRelease-1>", self.handle_mouseup) return new x, y = self.window.canvas_coords() w, h = self.window.winfo_width(), self.window.winfo_height() # 2*radius should be < MIN_CARD_SIZE, and offset < radius radius = 30 offset = 19 # offset of center of circle from card edge left_coords = (x + offset, y + h / 2) right_coords = (x + w - offset, y + h / 2) top_coords = (x + w / 2, y + offset) bottom_coords = (x + w / 2, y + h - offset) all_coords = (top_coords, right_coords, bottom_coords, left_coords) bboxes = [(x - radius, y - radius, x + radius, y + radius) for x, y in all_coords] if self.edge_handles: # move the edge handles for i, box in enumerate(bboxes): # self.canvas.coords(handle, box[0], box[1], box[2], box[3]) self.canvas.delete(self.edge_handles[i]) self.edge_handles[i] = create_circle(box) # self.canvas.itemconfig(handle, bbox = box) else: # create new ones self.edge_handles = [create_circle(b) for b in bboxes] # have to do this every time, every time we recreate the edge handles self.viewport.fix_z_order() def get_text(self): "gets the text from the actual editor, which may not be saved yet" return self.text.get("0.0", END) def save_text(self): # get text from window text = self.get_text() if text != self.card.text: self.card.text = text self.gpfile.commit() def canvas_coords(self): return self.window.canvas_coords() def start_moving(self, event): # set up state for a drag self.moving = True self.foocoords = (event.x, event.y) self.set_moving_edgescroll_callback() def edge_scroll(self): # if any edges are too close to the edge, move and scroll the canvas canvas_coords = self.canvas_coords() relative_mouse_pos = self.foocoords canvas_mouse_coords = ( canvas_coords[0] + relative_mouse_pos[0] + self.frame_thickness, canvas_coords[1] + relative_mouse_pos[1] + self.frame_thickness, ) scroll_x, scroll_y = self.viewport.edge_scroll(canvas_mouse_coords) # move the opposite direction the viewport scrolled scroll_x, scroll_y = -scroll_x, -scroll_y # print 'card.edgescroll x y', scroll_x, scroll_y, 'relative_mouse_pos', relative_mouse_pos self.window.move(scroll_x, scroll_y) self.viewport.reset_scroll_region() self.set_moving_edgescroll_callback() def set_moving_edgescroll_callback(self): self.moving_edgescroll_id = self.text.after(10, self.edge_scroll) def cancel_moving_edgescroll_callback(self): self.text.after_cancel(self.moving_edgescroll_id) self.moving_edgescroll_id = None def mousedown(self, event): self.window.lift() def doubleclick(self, event): self.start_moving(event) return "break" def shiftmousedown(self, event): self.mousedown(event) self.start_moving(event) return "break" def mousemove(self, event): if self.moving: # coords are relative to card, not canvas if self.foocoords: delta = (event.x - self.foocoords[0], event.y - self.foocoords[1]) else: delta = (event.x, event.y) self.window.move(delta[0], delta[1]) self.geometry_callback() self.viewport.reset_scroll_region() return "break" def mouseup(self, event): if self.moving: self.moving = False new_coords = self.canvas_coords() self.card.x, self.card.y = new_coords[0], new_coords[1] self.gpfile.commit() self.cancel_moving_edgescroll_callback() self.geometry_callback() # next several functions are bound to the circular edge handles def handle_click(self, event): # create new edge self.new_edge = ViewportEdge(self.viewport, self.gpfile, None, self, None) self.new_edge.mousemove(event) # give it a real start pos def handle_shift_click(self, event): self.handle_click(event) self.new_edge.make_new_card = True def handle_mousemove(self, event): if self.new_edge: self.new_edge.mousemove(event) def handle_mouseup(self, event): if self.new_edge: self.new_edge.mouseup(event) self.new_edge = None def configure(self, event): self.redraw_edge_handles() def focusin(self, event): self.editing = True def focusout(self, event): self.editing = False self.save_text() def ctrldelete(self, event): title_sample = self.get_text().split("\n", 1)[0] if len(title_sample) > 20: title_sample = title_sample[:20] + "..." # delete the card if tkMessageBox.askokcancel("Delete?", 'Delete card "%s" and all its edges?' % title_sample): for handle in self.edge_handles: self.canvas.delete(handle) self.deletion_slot.signal() self.viewport.remove_card(self) self.card.delete() self.window.destroy() self.gpfile.commit() return "break" def save_card(self): # grab values from self.window, # and put them in the model.card self.card.x, self.card.y = self.window.canvas_coords() self.card.w, self.card.h = self.window.winfo_width(), self.window.winfo_height() self.geometry_callback() # here so it gets called after resizing self.gpfile.commit() def add_geom_signal(self, fn): return self.geom_slot.add(fn) def remove_geom_signal(self, handle): self.geom_slot.remove(handle) def add_deletion_signal(self, fn): return self.deletion_slot.add(fn) def remove_deletion_signal(self, handle): self.deletion_slot.remove(handle) def geometry_callback(self): x, y = self.canvas_coords() w, h = self.window.winfo_width(), self.window.winfo_height() self.geom_slot.signal(self, x, y, w, h) def highlight(self): self.text.config(background="#ffffa2") def unhighlight(self): self.text.config(background="white")
frm_log = Frame(mw, width=480, height=330, highlightbackground='gray', highlightcolor='black', highlightthickness=2) frm_log.place(x=40, y=430, width=480, height=330) log_text_area = ScrolledText( master=frm_log, # wrap=mw.WORD, highlightthickness=0) log_text_area.configure(state='disabled') log_text_area.pack(fill=BOTH) log_text_area.bind('<Command-a>', select_all_text) # log_text_area.bind('<Control-a>', select_all_text) # ======== Odometry and Measurement Logging Frame ======== frm_pos = Frame(mw, width=511, height=330, highlightbackground='gray', highlightcolor='black', highlightthickness=2) frm_pos.place(x=603, y=430, width=511, height=330) pos_text_area = ScrolledText( master=frm_pos, # wrap=mw.WORD, highlightthickness=0)
class TextBox: def __init__(self): self.WIDTH = 600 self.HEIGHT = 800 self.FONT = "helvetica" self.FONT_SIZE = 12 # colours specified as RGB fractions self.bg_input = [1, 1, 1] self.fg_input = [0, 0, 0] self.bg_article = [0, 0, 0] self.fg_min_article = [0.5, 0.5, 0.5] self.fg_max_article = [0.9, 0.9, 0.9] self.fg_solution_article = [1, 1, 1] #[0.3, 0.5, 1.0] #[1, 0.7, 0.4] invert = False if invert: self.bg_input = [1. - v for v in self.bg_input] self.fg_input = [1. - v for v in self.fg_input] self.bg_article = [1. - v for v in self.bg_article] self.fg_min_article = [1. - v for v in self.fg_min_article] self.fg_max_article = [1. - v for v in self.fg_max_article] self.text = "" # what is shown in the box self.allText = "" # the text for the entire article self.sentences = [] # list of sentences in article # dictionary mapping from size to k-hot encoding indicating # which sentences are in the summary self.solutions = [] # (not used) how much weight is put on each sentence self.weights = [] self.only_summary = True self.summary_size = 1 self.summary_coherence = 0.0 self.summary_independence = 0.8 self.summarizer = Summarizer(parent=self) self.root = Tk() self.draw(init=True) #self.root.mainloop() def draw(self, init=False): if init: # show main article body self.tk_article = ScrolledText(self.root) # let user paste and enter text self.tk_user_input = ScrolledText(self.root) self.tk_summary_size_scale = Scale(self.root) self.tk_summary_size_scale_label = Label(self.root, text="Length") self.tk_summary_coherence_scale = Scale(self.root) self.tk_summary_coherence_scale_label = Label(self.root, text="Coherence") self.tk_summary_independence_scale = Scale(self.root) self.tk_summary_independence_scale_label = Label( self.root, text="Independence") self.tk_toggle_view = Button(self.root, text="more", command=self.handleToggleView) self.tk_recalculate = Button(self.root, text="Update", command=self.handleRecalculate) self.root.geometry("%dx%d" % (self.WIDTH, self.HEIGHT)) self.root.title("QuickReader V4") self.tk_article.configure(width=25, height=6, bd=0, highlightthickness=0, wrap="word", font=self.FONT) self.tk_user_input.configure(width=25, height=3, bd=0, highlightthickness=0, wrap="word", font=self.FONT) self.tk_summary_size_scale.configure( bd=0, from_=0, to=20, orient=HORIZONTAL, sliderrelief=FLAT, command=lambda event: self.handleSlider( self.tk_summary_size_scale.get())) ###### self.tk_summary_coherence_scale.configure( bd=0, from_=0, to=1, orient=HORIZONTAL, sliderrelief=FLAT, resolution=0.05, command=lambda event: self.handleCoherenceSlider( self.tk_summary_coherence_scale.get())) self.tk_summary_coherence_scale.set(self.summary_coherence) ###### self.tk_summary_independence_scale.configure( bd=0, from_=0, to=1.5, orient=HORIZONTAL, sliderrelief=FLAT, resolution=0.05, command=lambda event: self.handleIndependenceSlider( self.tk_summary_independence_scale.get())) self.tk_summary_independence_scale.set(self.summary_independence) # set colours self.root.configure(background="black") self.tk_summary_size_scale.configure(troughcolor="#444444", fg="black", background="white", activebackground="#bbbbbb") self.tk_summary_coherence_scale.configure( troughcolor="#444444", fg="black", background="white", activebackground="#bbbbbb") self.tk_summary_independence_scale.configure( troughcolor="#444444", fg="black", background="white", activebackground="#bbbbbb") self.tk_article.configure(bg=toHex(self.bg_article), fg="white", insertbackground="blue") self.tk_article.vbar.configure(bg="white", width=10, troughcolor="black") self.tk_user_input.configure(bg=toHex(self.bg_input), fg=toHex(self.fg_input), insertbackground="blue") self.tk_user_input.vbar.configure(bg="white", width=10, troughcolor="black") self.tk_user_input.focus() self.tk_user_input.bind("<KeyRelease-Return>", (lambda event: self.handleUserInput( self.tk_user_input.get("0.0", END)))) self.root.bind("<Configure>", self.resize) def setText(self, text, redraw=False): self.text = text if redraw: self.updateArticleInfo() def setSentences(self, sentences, redraw=False): self.sentences = sentences if redraw: self.updateArticleInfo() def setSolutions(self, solutions, redraw=False): self.solutions = solutions if redraw: self.updateArticleInfo() def setWeights(self, weights, redraw=False): self.weights = weights if redraw: self.updateArticleInfo() def handleToggleView(self): print("View toggle!") self.only_summary = not self.only_summary if self.only_summary: self.tk_toggle_view.configure(text="more") else: self.tk_toggle_view.configure(text="less") self.updateSummary() def handleRecalculate(self): print("Update!") self.handleUserInput(self.allText) def handleSlider(self, value): print("Slider:", value) self.summary_size = value self.updateSummary() def handleCoherenceSlider(self, value): print("Coherence Slider:", value) self.summary_coherence = value #self.updateSummary() def handleIndependenceSlider(self, value): print("Independence Slider:", value) self.summary_independence = value #self.updateSummary() def updateSummary(self): l = self.summary_size if self.only_summary and l != 0: self.setText('\n\n'.join([ self.sentences[i] for i in range(len(self.sentences)) if self.solutions[l][i] == 1 ])) else: self.setText(self.allText, redraw=False) self.updateArticleInfo() self.setWeights([0. for _ in self.sentences], redraw=True) self.tk_article.yview_moveto(0) #vbar.set(0, 0) #configure(jump=0) def handleUserInput(self, inStr): self.tk_user_input.delete("0.0", END) if inStr.strip() == "": return text = inStr text = ''.join([ch for ch in text if ord(ch) < 128]) self.setText(text, redraw=False) self.setSolutions([], redraw=False) self.setWeights([], redraw=True) text, sentences, solutions = self.summarizer.summarize( text, coherence_weight=self.summary_coherence, independence_weight=self.summary_independence, size_weight=1., beam_width=3, hard_size_limit=None) self.allText = text self.sentences = sentences self.solutions = solutions self.solutions[0] = [1. for _ in sentences] # get max length for summary max_len = max(solutions.keys()) set_len = min(max_len, 3) self.tk_summary_size_scale.configure(from_=0, to=max_len) self.tk_summary_size_scale.set(set_len) self.summary_size = set_len # text: all the text in one long string # sentences: the text split up into a list of sentences # solution: dictionary mapping summary size to a one-hot vector over the sentences, indicating # which sentences are included in the summarization # the text should be the same, but update it anyways since it needs to contain the # exact same stuff as the sentences self.updateSummary() #self.updateArticleInfo() def resize(self, event=[]): LINEH = 20.0 pixelX = self.root.winfo_width() pixelY = self.root.winfo_height() bf = 5 # buffer size in pixels # update find_icon, wiki_icon, and graph_icon # set toggle and recalculate button toggleW = 50 toggleH = 35 * 1 self.tk_toggle_view.place(x=pixelX - toggleW, y=0, width=toggleW, height=toggleH) updateW = 50 updateH = 35 * 2 self.tk_recalculate.place(x=pixelX - updateW, y=toggleH, width=updateW, height=updateH) buttonH = toggleH + updateH labelW = 90 # set position of size scale scaleW = pixelX - updateW - labelW scaleH = 35 self.tk_summary_size_scale.place(x=labelW, y=0, width=scaleW, height=scaleH) self.tk_summary_size_scale_label.place(x=0, y=0, width=labelW, height=scaleH) # set position of coherence scale coherenceW = pixelX - updateW - labelW coherenceH = 35 self.tk_summary_coherence_scale.place(x=labelW, y=scaleH, width=scaleW, height=scaleH) self.tk_summary_coherence_scale_label.place(x=0, y=scaleH, width=labelW, height=coherenceH) # set position of independence scale independenceW = pixelX - updateW - labelW independenceH = 35 self.tk_summary_independence_scale.place(x=labelW, y=scaleH + coherenceH, width=scaleW, height=scaleH) self.tk_summary_independence_scale_label.place(x=0, y=scaleH + coherenceH, width=labelW, height=independenceH) # update user input inputW = pixelX inputH = int(3.0 * LINEH) self.tk_user_input.place(x=0, y=pixelY - inputH, width=inputW, height=inputH) # update article articleW = pixelX articleH = pixelY - inputH - scaleH - coherenceH - independenceH self.tk_article.place(x=0, y=scaleH + coherenceH + independenceH, width=articleW, height=articleH) def updateArticleInfo(self): self.articleClear() self.articleCat(self.text) if self.weights != []: self.articleColour() self.root.update() def articleClear(self): self.tk_article.delete("1.0", END) self.tk_article.update() self.root.update() return def articleCat(self, inStr): self.tk_article.insert(END, inStr) self.tk_article.yview(END) def articleColour(self): ''' solution = self.solutions[self.summary_size] allText = self.text #self.tk_article.get('1.0', 'end-1c') # make sure weights are normalised maxW = max(self.weights) minW = min(self.weights) weights = self.weights if maxW != minW: weights = [(v-minW)/(maxW-minW) for v in self.weights] for i in range(len(self.sentences)): if self.only_summary and solution[i] != 1.: continue s = self.sentences[i] if len(s.strip()) == 0: continue tagNameA = ''.join([random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(10)]) L_Size = 12 # if solution[i] == 1 else 10 L_Colour = blend(self.fg_min_article, self.fg_max_article, weights[i]) L_Colour = self.fg_solution_article if solution[i] == 1 else L_Colour countVar = StringVar(self.root) pos = self.tk_article.search(s, "1.0", stopindex="end", count=countVar) self.tk_article.tag_add(tagNameA, pos, "{} + {}c".format(pos, countVar.get())) bolding = "normal" #"bold" if self.solution[i] == 1 else "normal" # font = (self.FONT, L_Size, bolding) self.tk_article.tag_config(tagNameA, foreground=toHex(L_Colour), font=font)#self.FONT+' %s'%(L_Size)) self.root.update() ''' solution = self.solutions[self.summary_size] allText = self.text #self.tk_article.get('1.0', 'end-1c') #print("=========") for i in range(len(self.sentences)): if self.only_summary and solution[i] != 1.: continue s = self.sentences[i] #if len(s.strip()) == 0: # continue #print("- ", s) tagNameA = ''.join([ random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(10) ]) L_Size = self.FONT_SIZE # if solution[i] == 1 else 10 L_Colour = self.fg_solution_article if solution[ i] == 1 else self.fg_min_article #print("\t", L_Colour) countVar = StringVar(self.root) pos = self.tk_article.search(s, "1.0", stopindex="end", count=countVar) self.tk_article.tag_add(tagNameA, pos, "{} + {}c".format(pos, countVar.get())) bolding = "normal" #"bold" if self.solution[i] == 1 else "normal" # font = (self.FONT, L_Size, bolding) self.tk_article.tag_config(tagNameA, foreground=toHex(L_Colour), font=font) #self.FONT+' %s'%(L_Size)) self.root.update()
def __init__(self, master): Client.__init__(self) self.started = False # use it to not try stopping if didn't start self.parent = master # used to distroy it on exit master.title("TomIRC") # app's title master.resizable(0, 0) # user cannot resize it # master.config(width = 720, height = 526) # master.grid_propagate(False) # doesn't change size because of inner elements result = InitialDialog(master, "Connection settings").result if not result: self.onExit() return self.started = True self.start(result[0], result[1]) self.name = result[2] master.protocol("WM_DELETE_WINDOW", self.onExit) # add a menu menu = Menu(master) master.config(menu = menu) filemenu = Menu(menu) menu.add_cascade(label = "File", menu = filemenu) filemenu.add_command(label = "Change your username", command = self.changeName) filemenu.add_separator() filemenu.add_command(label = "Quit", command = self.onExit) menu.add_command(label = "About", command = self.aboutBox) # use a menu entry as an information bar menu.add_command(label = " ", state = DISABLED) menu.add_command(label = "Connected to %s:%s as %s" % (result[0], result[1],\ self.name), state = DISABLED, background = "gray", \ font = tkFont.Font(family = "Times", weight = tkFont.BOLD,\ size = 10)) menu.add_command(label = " ",\ state = DISABLED) menu.add_command(label = " Connected users ",\ state = DISABLED, background = "gray", \ font = tkFont.Font(family = "Times", weight = tkFont.BOLD, \ size = 10)) menu.config(disabledforeground = "#777") self.menu = menu # list of connected users self.connectedUsers = StringVar() # used to update the userList self.userList = Listbox(master, height = 15, width = 21, selectmode = MULTIPLE, \ listvariable = self.connectedUsers) self.userList.bind('<<ListboxSelect>>', self.onListSelect) # self.connectedUsers.set("default_user\n" + self.name) # add widget for displaying incoming text text = ScrolledText(master, height = 20, width = 75, state = DISABLED) text.tag_config("a", background = "lightgray") # set a tag for the author text.tag_config('s', background = "darkgray") # set a tag for the server self.display = text # add the text input text = ScrolledText(master, height = 5, width = 75) text.bind('<KeyRelease-Return>', self.sendMessage) text.focus_set() self.input = text # add a label to state errors and warnings self.infoLabel = StringVar(value = "Registered successfully...") label = Label(master, textvariable = self.infoLabel, anchor = W, fg = "#555") label.grid(row = 2, column = 0, columnspan = 2, sticky = W) self.display.grid(row = 0, column = 0, sticky = N) self.input.grid(row = 1, column = 0) self.userList.grid(row = 0, column = 1, rowspan = 2, sticky = N + S) self.send("REG " + self.name) # register the user self.populateList()
class ViewportCard(object): ''' Manages the graphical representation of a card in a Tkinter canvas. Creates and destroys items as necessary, facilitates editing, and so on and so forth. Members: * card: model.Card * viewport: GPViewport * gpfile: gpfile.GraphPaperFile, contains model.graph() * canvas: TKinter canvas we get drawn on * editing: bool, text is being edited * moving: bool, being dragged * moving_edgescroll_id: callback id to scroll periodically when hovering near edge of screen * resize_state: {} * resize_edgescroll_id: as moving_edgescroll_id * slot: calls callbacks whenever geometry changes * new_edge: if an edge is being dragged out from a handle, this is it. * card_after_new_edge: bool, if we should make a new card when edge is dropped. ''' def __init__(self, viewport, gpfile, card): self.card = card self.viewport = viewport self.gpfile = gpfile self.canvas = viewport.canvas self.draw() self.editing = False self.moving = False self.moving_edgescroll_id = None self.resize_state = None self.resize_edgescroll_id = None # slot triggered when geometry (pos/size) changes # fn args: (self, x, y, w, h) self.geom_slot = Slot() self.deletion_slot = Slot() self.new_edge = None def draw(self): self.frame_thickness = 5 self.window = ResizableCanvasFrame(self.canvas, self.card.x, self.card.y, self.card.w, self.card.h, min_width=MIN_CARD_SIZE, min_height=MIN_CARD_SIZE) self.text = ScrolledText(self.window, wrap=WORD) self.text.pack(expand=1, fill='both') # set up text for editing, dragging, deleting self.text.bind("<Button-1>", self.mousedown) self.text.bind("<Shift-Button-1>", self.shiftmousedown) self.text.bind("<Double-Button-1>", self.doubleclick) self.text.bind("<B1-Motion>", self.mousemove) self.text.bind("<ButtonRelease-1>", self.mouseup) self.text.bind("<FocusIn>", self.focusin) self.text.bind("<FocusOut>", self.focusout) self.text.bind("<Control-Delete>", self.ctrldelete) self.text.insert(END, self.card.text) # set up frame for resizing self.window.bind('<Configure>', self.configure) self.window.save_callback = self.save_card # draw edge handles self.edge_handles = None #self.redraw_edge_handles() def redraw_edge_handles(self): ''' Either creates or modifies the edge handles, little circles poking out the side of the card, based on the current position and width. self.edge_handles is a list of itemids of the circles in (top, right, bottom, left) order. ''' def create_circle(bbox): # create circle suitable for edge-handle use new = self.canvas.create_oval(bbox[0], bbox[1], bbox[2], bbox[3], fill='green', outline='') self.canvas.addtag_withtag('card_handle_tag', new) # for z-ordering self.canvas.tag_bind(new, '<Button-1>', self.handle_click) self.canvas.tag_bind(new, '<Shift-Button-1>', self.handle_shift_click) self.canvas.tag_bind(new, '<B1-Motion>', self.handle_mousemove) self.canvas.tag_bind(new, '<ButtonRelease-1>', self.handle_mouseup) return new x, y = self.window.canvas_coords() w, h = self.window.winfo_width(), self.window.winfo_height() # 2*radius should be < MIN_CARD_SIZE, and offset < radius radius = 30 offset = 19 # offset of center of circle from card edge left_coords = (x + offset, y + h / 2) right_coords = (x + w - offset, y + h / 2) top_coords = (x + w / 2, y + offset) bottom_coords = (x + w / 2, y + h - offset) all_coords = (top_coords, right_coords, bottom_coords, left_coords) bboxes = [(x - radius, y - radius, x + radius, y + radius) for x, y in all_coords] if self.edge_handles: # move the edge handles for i, box in enumerate(bboxes): #self.canvas.coords(handle, box[0], box[1], box[2], box[3]) self.canvas.delete(self.edge_handles[i]) self.edge_handles[i] = create_circle(box) #self.canvas.itemconfig(handle, bbox = box) else: # create new ones self.edge_handles = [create_circle(b) for b in bboxes] # have to do this every time, every time we recreate the edge handles self.viewport.fix_z_order() def get_text(self): "gets the text from the actual editor, which may not be saved yet" return self.text.get('0.0', END) def save_text(self): # get text from window text = self.get_text() if text != self.card.text: self.card.text = text self.gpfile.commit() def canvas_coords(self): return self.window.canvas_coords() def start_moving(self, event): # set up state for a drag self.moving = True self.foocoords = (event.x, event.y) self.set_moving_edgescroll_callback() def edge_scroll(self): # if any edges are too close to the edge, move and scroll the canvas canvas_coords = self.canvas_coords() relative_mouse_pos = self.foocoords canvas_mouse_coords = (canvas_coords[0] + relative_mouse_pos[0] + self.frame_thickness, canvas_coords[1] + relative_mouse_pos[1] + self.frame_thickness) scroll_x, scroll_y = self.viewport.edge_scroll(canvas_mouse_coords) # move the opposite direction the viewport scrolled scroll_x, scroll_y = -scroll_x, -scroll_y #print 'card.edgescroll x y', scroll_x, scroll_y, 'relative_mouse_pos', relative_mouse_pos self.window.move(scroll_x, scroll_y) self.viewport.reset_scroll_region() self.set_moving_edgescroll_callback() def set_moving_edgescroll_callback(self): self.moving_edgescroll_id = self.text.after(10, self.edge_scroll) def cancel_moving_edgescroll_callback(self): self.text.after_cancel(self.moving_edgescroll_id) self.moving_edgescroll_id = None def mousedown(self, event): self.window.lift() def doubleclick(self, event): self.start_moving(event) return 'break' def shiftmousedown(self, event): self.mousedown(event) self.start_moving(event) return "break" def mousemove(self, event): if self.moving: # coords are relative to card, not canvas if self.foocoords: delta = (event.x - self.foocoords[0], event.y - self.foocoords[1]) else: delta = (event.x, event.y) self.window.move(delta[0], delta[1]) self.geometry_callback() self.viewport.reset_scroll_region() return "break" def mouseup(self, event): if self.moving: self.moving = False new_coords = self.canvas_coords() self.card.x, self.card.y = new_coords[0], new_coords[1] self.gpfile.commit() self.cancel_moving_edgescroll_callback() self.geometry_callback() # next several functions are bound to the circular edge handles def handle_click(self, event): # create new edge self.new_edge = ViewportEdge(self.viewport, self.gpfile, None, self, None) self.new_edge.mousemove(event) # give it a real start pos def handle_shift_click(self, event): self.handle_click(event) self.new_edge.make_new_card = True def handle_mousemove(self, event): if self.new_edge: self.new_edge.mousemove(event) def handle_mouseup(self, event): if self.new_edge: self.new_edge.mouseup(event) self.new_edge = None def configure(self, event): self.redraw_edge_handles() def focusin(self, event): self.editing = True def focusout(self, event): self.editing = False self.save_text() def ctrldelete(self, event): title_sample = self.get_text().split('\n', 1)[0] if len(title_sample) > 20: title_sample = title_sample[:20] + '...' # delete the card if tkMessageBox.askokcancel( "Delete?", "Delete card \"%s\" and all its edges?" % title_sample): for handle in self.edge_handles: self.canvas.delete(handle) self.deletion_slot.signal() self.viewport.remove_card(self) self.card.delete() self.window.destroy() self.gpfile.commit() return "break" def save_card(self): # grab values from self.window, # and put them in the model.card self.card.x, self.card.y = self.window.canvas_coords() self.card.w, self.card.h = self.window.winfo_width( ), self.window.winfo_height() self.geometry_callback() # here so it gets called after resizing self.gpfile.commit() def add_geom_signal(self, fn): return self.geom_slot.add(fn) def remove_geom_signal(self, handle): self.geom_slot.remove(handle) def add_deletion_signal(self, fn): return self.deletion_slot.add(fn) def remove_deletion_signal(self, handle): self.deletion_slot.remove(handle) def geometry_callback(self): x, y = self.canvas_coords() w, h = self.window.winfo_width(), self.window.winfo_height() self.geom_slot.signal(self, x, y, w, h) def highlight(self): self.text.config(background='#ffffa2') def unhighlight(self): self.text.config(background='white')
class UploadWizard(Wizard): def __init__(self, root, data): self.root = root self.data = data self.secure = False super(UploadWizard, self).__init__( width=450, height=300, cancelcommand=self._handle_cancel, finishcommand=self._handle_finish, ) self.servers = ServerList() self.server_lbox = None self.upthread = None self.old_upload_state = None self.setup_gui() def setup_gui(self): self.title("Upload Wizard") self.protocol("WM_DELETE_WINDOW", self._handle_cancel) self.setup_gui_server_pane() self.setup_gui_user_pane() self.setup_gui_program_pane() self.setup_gui_upload_pane() def setup_gui_server_pane(self): fr = self.add_pane( 'server', 'Select Server', entrycommand=self._enter_server_pane ) fr.config(padx=20, pady=20) self.ssl_enable = IntVar() lbox_lbl = Label(fr, text="Select a Server to upload to:") self.server_lbox = ScrolledListbox( fr, horiz_scroll=False, width=20, highlightthickness=1) muck_lbl = Label(fr, text="Name") host_lbl = Label(fr, text="Host") port_lbl = Label(fr, text="Port") svalid = (self.register(self._serv_validate)) pvalid = (self.register(self._port_validate), '%P') self.muck_entry = Entry( fr, width=30, validate=ALL, validatecommand=svalid) self.host_entry = Entry( fr, width=30, validate=ALL, validatecommand=svalid) self.port_entry = Entry( fr, width=10, validate=ALL, validatecommand=pvalid) self.port_entry.insert(END, '8888') self.ssl_cb = Checkbutton( fr, text="SSL", variable=self.ssl_enable, highlightthickness=3, command=self._update_server_buttons, ) self.serv_del = Button(fr, text="-", width=1, command=self._del_server) self.serv_add = Button(fr, text="+", width=1, command=self._add_server) self.serv_save = Button(fr, text="Save", command=self._save_server) ToolTip(self.serv_del, "Delete selected Favorite Server") ToolTip(self.serv_add, "Enter a new Server") ToolTip(self.serv_save, "Save as a Favorite Server") self.server_lbox.bind('<<ListboxSelect>>', self._server_listbox_select) lbox_lbl.grid(row=0, column=0, sticky=N+W) self.server_lbox.grid( row=1, column=0, rowspan=8, padx=5, sticky=N+S+E+W) muck_lbl.grid(row=1, column=1, sticky=W, padx=5) self.muck_entry.grid(row=2, column=1, columnspan=3, sticky=E+W, padx=5) host_lbl.grid(row=3, column=1, sticky=W, padx=5) self.host_entry.grid(row=4, column=1, columnspan=3, sticky=E+W, padx=5) port_lbl.grid(row=5, column=1, sticky=W, padx=5) self.port_entry.grid(row=6, column=1, columnspan=2, sticky=E+W, padx=5) self.ssl_cb.grid(row=6, column=3, sticky=E, padx=5) self.serv_del.grid(row=8, column=1, sticky=N+W, padx=5) self.serv_add.grid(row=8, column=2, sticky=N+W, padx=5) self.serv_save.grid(row=8, column=3, sticky=N+E, padx=5) fr.grid_columnconfigure(2, weight=1, minsize=50) fr.grid_rowconfigure(7, weight=1) self.server_lbox.focus() return fr def setup_gui_user_pane(self): fr = self.add_pane( 'user', 'Select a user', entrycommand=self._enter_user_pane ) fr.config(padx=20, pady=20) lbox_lbl = Label(fr, text="Select a User to upload to:") self.user_lbox = ScrolledListbox(fr, horiz_scroll=False, width=20) user_lbl = Label(fr, text="UserName") pass_lbl = Label(fr, text="Password") uvalid = (self.register(self._user_validate)) self.user_entry = Entry( fr, width=30, validate=ALL, validatecommand=uvalid) self.pass_entry = Entry( fr, width=30, show="*", validate=ALL, validatecommand=uvalid) self.user_del = Button(fr, text="-", width=1, command=self._del_user) self.user_add = Button(fr, text="+", width=1, command=self._add_user) self.user_save = Button(fr, text="Save", command=self._save_user) ToolTip(self.user_del, "Delete selected User") ToolTip(self.user_add, "Enter a new User") ToolTip(self.user_save, "Save User Info") self.user_lbox.bind('<<ListboxSelect>>', self._user_listbox_select) lbox_lbl.grid(row=0, column=0, sticky=N+W) self.user_lbox.grid(row=1, column=0, rowspan=8, padx=5, sticky=N+S+E+W) user_lbl.grid(row=1, column=1, sticky=W, padx=5) self.user_entry.grid(row=2, column=1, columnspan=3, sticky=E+W, padx=5) pass_lbl.grid(row=3, column=1, sticky=W, padx=5) self.pass_entry.grid(row=4, column=1, columnspan=3, sticky=E+W, padx=5) self.user_del.grid(row=6, column=1, sticky=N+W, padx=5) self.user_add.grid(row=6, column=2, sticky=N+W, padx=5) self.user_save.grid(row=6, column=3, sticky=N+E, padx=5) fr.grid_columnconfigure(2, weight=1, minsize=50) fr.grid_rowconfigure(5, weight=1) return fr def setup_gui_program_pane(self): fr = self.add_pane( 'program', 'Program Info', entrycommand=self._enter_program_pane ) pvalid = (self.register(self._program_validate)) fr.config(padx=20, pady=20) prog_lbl = Label(fr, text="Program Name or DBRef") self.prog_entry = Entry( fr, width=30, validate=ALL, validatecommand=pvalid) global previous_progname self.prog_entry.insert(END, previous_progname) prog_lbl.grid(row=0, column=0, sticky=W+S) self.prog_entry.grid(row=1, column=0, sticky=N+E+W) fr.grid_columnconfigure(0, weight=1) fr.grid_rowconfigure(2, weight=1) return fr def setup_gui_upload_pane(self): fr = self.add_pane( 'upload', 'Uploading', entrycommand=self._enter_upload_pane ) fr.config(padx=20, pady=20) self.upload_lbl = Label( fr, text="", justify=LEFT, anchor=W, wraplength=400) self.progressbar = ProgressBar( fr, length=300, value=10.0, maximum=100.0, mode=INDETERMINATE, ) self.console_log = ScrolledText( fr, font='TkFixedFont', relief=SUNKEN, borderwidth=2, background="black", foreground="white", width=1, height=1, insertontime=0, takefocus=0, cursor='arrow', ) ro_binds = [ "<Key>", "<<Cut>>", "<<Clear>>", "<<Paste>>", "<<PasteSelection>>", "<Double-Button-1>", ] for bind in ro_binds: self.console_log.bind(bind, lambda e: "break") self.upload_lbl.grid(row=0, column=0, sticky=W+S) self.progressbar.grid(row=1, column=0, sticky=N+E+W, padx=15, pady=5) self.console_log.grid(row=2, column=0, sticky=N+S+E+W) fr.grid_columnconfigure(0, weight=1) fr.grid_rowconfigure(2, weight=1) return fr def _enter_server_pane(self): self.set_finish_enabled(False) self.set_next_enabled(False) self.set_next_text() self.set_default_button("next") self.set_finish_text("Done") self._populate_server_listbox() if self.server_lbox.size() > 0: self.server_lbox.focus() else: self.muck_entry.focus() self._update_server_buttons() def _enter_user_pane(self): self.set_finish_enabled(False) self.set_next_enabled(False) self.set_next_text() self.set_default_button("next") self._populate_user_listbox() if self.user_lbox.size() > 0: self.user_lbox.focus() else: self.user_entry.focus() self._update_user_buttons() def _enter_program_pane(self): self.set_finish_enabled(False) self.set_next_enabled(False) self.set_next_text("Upload") self.set_default_button("next") self.prog_entry.focus() def _enter_upload_pane(self): self.set_default_button("finish") self.set_next_text() self.set_prev_enabled(False) self.set_finish_enabled(False) self._upload_start() global previous_progname previous_progname = self.prog_entry.get() def _populate_server_listbox(self): self.server_lbox.delete(0, END) for serv in self.servers.get_servers(): self.server_lbox.insert(END, str(serv)) def _update_server_listbox(self): sel = self.server_lbox.curselection() self._populate_server_listbox() if sel: self.server_lbox.selection_set(sel[0]) self._update_server_buttons() def _server_listbox_select(self, event=None): try: sel = int(self.server_lbox.curselection()[0]) servers = self.servers.get_servers() serv = servers[sel] self.muck_entry.delete(0, END) self.host_entry.delete(0, END) self.port_entry.delete(0, END) self.muck_entry.insert(END, serv.name) self.host_entry.insert(END, serv.host) self.port_entry.insert(END, serv.port) self.ssl_enable.set(serv.ssl) self._update_server_buttons() except (ValueError, IndexError): return def _update_server_buttons(self, event=None): add_state = 'normal' del_state = 'normal' save_state = 'normal' items = self.server_lbox.curselection() if not items: del_state = 'disabled' if not self.muck_entry.get(): if not self.host_entry.get(): if self.port_entry.get() == '8888': if not self.ssl_enable.get(): add_state = 'disabled' if not self.host_entry.get() or not self.port_entry.get(): save_state = 'disabled' self.serv_del.config(state=del_state) self.serv_add.config(state=add_state) self.serv_save.config(state=save_state) self.set_next_enabled( bool(items or (self.host_entry.get() and self.port_entry.get())) ) def _serv_validate(self): self.after_idle(self._update_server_buttons) return True def _port_validate(self, val): self.after_idle(self._update_server_buttons) if val == '': return True try: val = int(val) return True except ValueError: self.bell() return False def _add_server(self): self.server_lbox.selection_clear(0, END) self.muck_entry.delete(0, END) self.host_entry.delete(0, END) self.port_entry.delete(0, END) self.port_entry.insert(END, '8888') self.ssl_enable.set('0') self.muck_entry.focus() self._update_server_buttons() def _del_server(self): del_confirmed = askyesno( "Delete Server", "Are you sure you want to delete this server?", parent=self ) if del_confirmed: try: sel = int(self.server_lbox.curselection()[0]) self.servers.del_server(sel) self.servers.save() self._update_server_listbox() except (ValueError, IndexError): self.bell() def _save_server(self): sel = -1 try: sel = int(self.server_lbox.curselection()[0]) self.servers.del_server(sel) self._update_server_listbox() except (ValueError, IndexError): pass server = ServerInfo( name=self.muck_entry.get(), host=self.host_entry.get(), port=self.port_entry.get(), use_ssl=self.ssl_enable.get() ) self.servers.add_server(server) self.servers.save() self._update_server_listbox() if sel >= 0: self.server_lbox.selection_set(sel) self._server_listbox_select() self._update_server_buttons() def _populate_user_listbox(self): host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) self.user_lbox.delete(0, END) if not serv: return for user in serv.get_users(): self.user_lbox.insert(END, user.user) def _update_user_listbox(self): sel = self.user_lbox.curselection() self._populate_user_listbox() if sel: self.user_lbox.selection_set(sel[0]) self._update_user_buttons() def _user_listbox_select(self, event=None): host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) if not serv: return try: sel = int(self.user_lbox.curselection()[0]) users = serv.get_users() user = users[sel] self.user_entry.delete(0, END) self.pass_entry.delete(0, END) self.user_entry.insert(END, user.user) self.pass_entry.insert(END, user.password) self._update_server_buttons() except (ValueError, IndexError): return def _update_user_buttons(self, event=None): add_state = 'normal' del_state = 'normal' save_state = 'normal' host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) if not serv: del_state = 'disabled' add_state = 'disabled' save_state = 'disabled' items = self.user_lbox.curselection() if not items: del_state = 'disabled' if not self.user_entry.get(): if not self.pass_entry.get(): add_state = 'disabled' if not self.user_entry.get(): save_state = 'disabled' self.user_del.config(state=del_state) self.user_add.config(state=add_state) self.user_save.config(state=save_state) self.set_next_enabled( bool(items or (self.user_entry.get() and self.pass_entry.get())) ) def _user_validate(self): self.after_idle(self._update_user_buttons) return True def _add_user(self): self.user_lbox.selection_clear(0, END) self.user_entry.delete(0, END) self.pass_entry.delete(0, END) self._update_user_buttons() self.user_entry.focus() def _del_user(self): del_confirmed = askyesno( "Delete User", "Are you sure you want to delete this user?", parent=self ) if del_confirmed: host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) if not serv: return try: sel = int(self.server_lbox.curselection()[0]) serv.del_user(sel) self.servers.save() self._update_user_listbox() except (ValueError, IndexError): self.bell() def _save_user(self): host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) if not serv: return serv.add_user( user=self.user_entry.get(), password=self.pass_entry.get(), ) self.servers.save() self._update_user_listbox() def _update_program_buttons(self, event=None): self.set_next_enabled(bool(self.prog_entry.get())) def _program_validate(self): self.after_idle(self._update_program_buttons) return True def _upload_start(self): force_ssl = bool(self.ssl_enable.get()) host = self.host_entry.get() port = int(self.port_entry.get()) user = self.user_entry.get() password = self.pass_entry.get() progname = self.prog_entry.get() self.upload_lbl.config(text="Connecting to %s:%s..." % (host, port)) self.progressbar.start() self.upthread = UploadThread( host, port, force_ssl, user, password, progname, self.data, ) self.upthread.start() self.old_upload_state = '' self._update_upload_state() def _update_upload_state(self): logtxt = self.upthread.get_log_text() if logtxt: self.console_log.insert(END, logtxt) self.console_log.see(END) state = self.upthread.state self.upload_lbl.config(text=self.upthread.status) if state in [UPLOAD_FAIL, UPLOAD_SUCCESS]: self.set_finish_enabled(True) self.set_cancel_enabled(False) else: self.after(100, self._update_upload_state) if state == UPLOADING: uploaded = self.upthread.bytes_uploaded total = self.upthread.total_bytes pcnt = float(uploaded) / total self.progressbar.config(value=pcnt) if state == self.old_upload_state: return self.old_upload_state = state if state == UPLOADING: self.progressbar.stop() self.progressbar.config(mode=DETERMINATE) elif state == UPLOAD_FAIL: self.progressbar.stop() self.progressbar.grid_forget() elif state == UPLOAD_SUCCESS: self.progressbar.stop() self.progressbar.config(mode=DETERMINATE) self.progressbar.config(value=100.0) def _handle_cancel(self): self.destroy() def _handle_finish(self): self.destroy()
class Globby_Text_Editor(tk.Frame): def __init__(self, parent_widget, settings): # some initial values # TODO this Values are obsolete since Project_Settings covers them # --> self.settings.projects_path self.hash_opened_filename = None self.opened_filename = None self.settings = settings self.edit_button_list=[ {'text':'new page', 'cmd':self.on_new_page, 'keytxt':'CTRL+n','hotkey':'<Control-n>'}, {'text':'del page', 'cmd':self.on_del_page, 'keytxt':'CTRL+n','hotkey':'<DELETE>'} , {'text':'save', 'cmd':self.on_save, 'keytxt':'CTRL+s','hotkey':'<Control-s>'}, {'text':'undo', 'cmd':self.on_undo, 'keytxt':'CTRL+z','hotkey':'<Control-z>'}, {'text':'redo', 'cmd':self.on_redo, 'keytxt':'CTRL+y','hotkey':'<Control-y>'}] self.syntax_button_list=[ {'text':'**bold**', 'cmd':self.on_tag_insert, 'open_tag':'**', 'close_tag':'**','keytxt':'CTRL+b','hotkey':'<Control-b>'}, {'text':'//italic//', 'cmd':self.on_tag_insert, 'open_tag':'//', 'close_tag':'//', 'keytxt':'CTRL+i','hotkey':'<Control-i>'}, {'text':'__underline__', 'cmd':self.on_tag_insert, 'open_tag':'__', 'close_tag':'__', 'keytxt':'CTRL+u','hotkey':'<Control-u>'}, {'text':'[Link]', 'cmd':self.on_tag_insert, 'open_tag':'[', 'close_tag':']', 'keytxt':'CTRL+l','hotkey':'<Control-l>'}, {'text':'¸¸sub¸¸', 'cmd':self.on_tag_insert, 'open_tag':'¸¸', 'close_tag':'¸¸', 'keytxt':'CTRL+d','hotkey':'<Control-d>'}, {'text':'^^upper^^', 'cmd':self.on_tag_insert, 'open_tag':'^^', 'close_tag':'^^', 'keytxt':'CTRL+q','hotkey':'<Control-q>'}, {'text':'-~smaller~-', 'cmd':self.on_tag_insert, 'open_tag':'-~', 'close_tag':'~-', 'keytxt':'CTRL+w','hotkey':'<Control-w>'}, {'text':'+~bigger~+', 'cmd':self.on_tag_insert, 'open_tag':'+~', 'close_tag':'~+', 'keytxt':'CTRL+e','hotkey':'<Control-e>'}, {'text':'~~strike_thru~~', 'cmd':self.on_tag_insert, 'open_tag':'~~', 'close_tag':'~~', 'keytxt':'CTRL+t','hotkey':'<Control-t>'} ] # build Widgets tk.Frame.__init__(self, parent_widget) self.pack(fill=tk.BOTH, expand=tk.YES) #self.baseframe = tk.Frame(parent_widget) #self.baseframe.pack(fill=tk.BOTH, expand=tk.YES) self.editor() self.button_frame() # start tracking text changes inside the editfield thread.start_new_thread(self.on_txt_changes, ('',)) def editor(self): """ combine some Widgets to an enhanced editor (incl. Scrollbar) --> self.text the text widget itself --> self.opened_file_label Label on top of the editfield to show the name of the current opened File It can be used to show textchanges """ # build widgets self.txtfrm = tk.Frame(self) self.txtfrm.pack(fill=tk.BOTH, side=tk.LEFT, expand=tk.YES) self.opened_file_label = tk.Label(self.txtfrm, text="No File chosen") self.opened_file_label.pack(fill=tk.X) self.text = ScrolledText(self.txtfrm, bg="white", undo=1, maxundo=30, wrap=tk.WORD) self.text.pack(fill=tk.BOTH, expand=tk.YES, side=tk.LEFT) self.text.insert(1.0, u"Please open a File to edit") # build first(reference -- new name??) hash for comparison on changes self.hash_opened_filename = hash(self.text.get(1.0,tk.END)) # Set focus on textwidget and move cursor to the upper left self.text.focus_set() self.text.mark_set(tk.INSERT, '0.0') # goto line self.text.see(tk.INSERT) # scroll to line def label_button_row(self, parent_widget=None, btnlst=None, start_count=0): """Build a 2 column table with a label beside each button in a row. Bind a keyboard sequence to the button command. Display this keyboard sequence on the label. todo: - think about a parameter for the widget to bind the Hotkeys - rename to: labled_button_row, draw_labled_button_row Parameter: --> parent_widget: Parent widget to place the table --> btnlst: Type: List of dicts representing a button Example: {'text':'**bold**', # displayed on the Button (string) 'cmd':self.on_tag_insert, # command 'open_tag':'**', # chars representing the beginning # of a tag for inserting (string) 'close_tag':'**', # chars representing the end # of a tag for inserting (string) 'keytxt':'CTRL+b', # displayed on the Label (string) 'hotkey':'<Control-b>'} # keyboard sequence (string) Note: The existence of 'open_tag' and 'close_tag' in btnlst decides which command is bound to the Button. If they aren't there 'cmd' must be a function without parameters!!! otherwise 'cmd' needs following parameters: otag = btn['open_tag'] ctag = btn['close_tag'] event = None # Placeholder for a keysequence --> start_count: Type: int Description: The table is relized with tkinter grid layout manager. start_count is used if there is already a grid (with a Label beside a button). start_count can add the automatic genrated buttons under the existing. In Globby_Editor it is used to put a label_button_row under a Tkinter menubutton(file choose, headlines). """ i = start_count for btn in btnlst: try: otag = btn['open_tag'] ctag = btn['close_tag'] event = None doit = lambda e=event, o=otag, c=ctag:self.on_tag_insert(e,o,c) tk.Button(parent_widget, text=btn['text'], command=doit, relief=tk.RIDGE ).grid(column=0, row=i, sticky=tk.W+tk.E) self.text.bind(btn['hotkey'],doit) except KeyError: tk.Button(parent_widget, text=btn['text'], command=btn['cmd'], relief=tk.RIDGE ).grid(column=0, row=i, sticky=tk.W+tk.E) tk.Label(parent_widget, text=btn['keytxt'], relief=tk.FLAT ).grid(column=1, row=i, sticky=tk.W) i +=1 def button_frame(self): """draws a frame to hold a edit- and syntax-buttons under each other """ self.btnfrm = tk.Frame(self) self.btnfrm.pack(fill=tk.BOTH, side=tk.LEFT) self.edit_buttons() self.syntax_buttons() def edit_buttons(self): """draws a frame with buttons for editing (save, undo, redo, open) """ # genrate a labelframe self.efrm = tk.LabelFrame(self.btnfrm, text="Edit Buttons") self.efrm.pack(fill=tk.BOTH, padx=5, pady=5) # generate a button with a pulldown menue to open a file to edit self.file_open_mbtn = tk.Menubutton(self.efrm, text='Open File') # generate the pulldown menue self.file_open_menu = tk.Menu(self.file_open_mbtn, postcommand=self.gen_file2edit_menu) # bind the pulldown menue to the menubutton self.file_open_mbtn.config(menu=self.file_open_menu, relief=tk.RIDGE) self.file_open_mbtn.grid(column=0,row=0, sticky=tk.W+tk.E) # label beside the Button to display the associated keyboard shortcut self.file_open_lbl = tk.Label(self.efrm, text='CTRL+o', relief=tk.FLAT) self.file_open_lbl.grid(column=1, row=0, sticky=tk.W+tk.E) # generate buttons as described in self.edit_button_list self.label_button_row(self.efrm, self.edit_button_list, 2) # bind keyboard shortcut to the menue self.text.bind('<Control-o>', lambda e: self.file_open_menu.tk_popup(e.x_root, e.y_root)) def gen_file2edit_menu(self): """generates a (new) menu bound to the file chooser button so every time when a project is created or deleted gen_choose_project_menu should be called """ # delete all existing menue entrys self.file_open_menu.delete(0,tk.END) proj_path = os.path.join(self.settings.projects_path, self.settings.current_project ) print "proj_path", proj_path for this_file in os.listdir(proj_path): splitted = os.path.splitext(this_file) if splitted[1] == ".txt" and splitted[0] != "menue": #print "this_file",this_file open_file = os.path.join(proj_path, this_file) do_it = lambda bla = open_file:self.on_open(bla) self.file_open_menu.add_command(label=splitted, command=do_it) def syntax_buttons(self): """draws a frame with buttons for insert (wiki)markup idea: new parameter for on_tag_insert() jump_in_between=True/False so a pulldown list for different levels of headlines arn't necessary """ # genrate a labelframe self.sfrm = tk.LabelFrame(self.btnfrm, text="Syntax Buttons") self.sfrm.pack(fill=tk.BOTH, padx=5, pady=5) # generate a button with a pulldown menue für headline Syntax self.headln_menubtn = tk.Menubutton(self.sfrm, text='= Headlines =') # generate the pulldown menue self.headln_menu = tk.Menu(self.headln_menubtn) # bind the pulldown menue to the menubutton self.headln_menubtn.config(menu=self.headln_menu, relief=tk.RIDGE) # generate menue entrys i=1 for entry in ('h1','h2','h3','h4','h5','h6'): otag = '\n\n'+'='*i+' ' ctag = ' '+'='*i+'\n\n' doit = lambda event=None, o=otag, c=ctag:self.on_tag_insert(event,o,c) self.headln_menu.add_command(label=entry, command=doit) i+=1 self.headln_menubtn.grid(column=0,row=0, sticky=tk.W+tk.E) # label beside the Button to display the associated keyboard shortcut self.headln_lbl = tk.Label(self.sfrm, text='CTRL+h', relief=tk.FLAT) self.headln_lbl.grid(column=1, row=0, sticky=tk.W+tk.E) # generate buttons as described in self.edit_button_list self.label_button_row(self.sfrm, self.syntax_button_list, 1) # bind keyboard shortcut to the menue self.text.bind('<Control-h>', lambda e: self.headln_menu.tk_popup(e.x_root, e.y_root)) def on_txt_changes(self, dummy_value=tk.NONE): """ tracks text changes inside the editfield by comparing hash values new name: visualize_txt_changes??? """ while True: new_hash = hash(self.text.get(1.0, tk.END)) if new_hash != self.hash_opened_filename: #print "changes" self.opened_file_label.configure(fg="red") else: #print "no changes" self.opened_file_label.configure(fg="black") sleep(0.2) def on_open(self, file_to_open=None): """- opens a *.txt file from project folder - generates a reference hash. - Brings the cursor to the upper left and show this position in the textfield Parameter: --> file_to_open: complete path for file to open idea: - rename file_to_open to openfile or file_to_open """ self.opened_file_to_open = file_to_open self.opened_file_label.configure(text=file_to_open) self.text.delete(1.0, tk.END) self.opened_filename = os.path.basename(file_to_open) # write file content into the editfield editfile = codecs.open(file_to_open,'r', 'utf-8') self.text.insert(1.0, editfile.read()) editfile.close() # generate reference hash for a comparison to track text changes self.hash_opened_filename = hash(self.text.get(1.0,tk.END)) self.text.edit_reset() # clear tk's undo/redo stacks self.text.focus_set() # focus to textfield self.text.mark_set(tk.INSERT, '0.0') # place cursor to upper left self.text.see(tk.INSERT) # and display this line def on_save(self): """ Safes the current edited file""" if self.opened_filename: print "on_safe_" print " self.opened_filename",self.opened_filename self.hash_opened_filename = hash(self.text.get(1.0,tk.END)) path_to_safe_file = os.path.join(self.settings.projects_path, self.settings.current_project, self.opened_filename) safefile = codecs.open(path_to_safe_file,'w', 'utf-8') safefile.write(self.text.get(1.0,tk.END)) safefile.close() self.text.edit_reset() #clear tk's undo/redo stacks else: showinfo('Globby Text Editor','No File to save \n\n' 'You need to choose a File before editing') def on_undo(self): try: # tk8.4 keeps undo/redo stacks self.text.edit_undo( ) # exception if stacks empty except tk.TclError: showinfo('Globby Text Editor', 'Nothing to undo') def on_redo(self): print "redo" try: # tk8.4 keeps undo/redo stacks self.text.edit_redo() # exception if stacks empty except tk.TclError: showinfo('Globby Text Editor', 'Nothing to redo') def on_new_page(self): """ Ask the user to name the new File, create a blank File and load it into the Editorwidget TODO: check if file with the new filename allready exists check if Filename contains Specialchars """ print "on_new_page" nfile_name = tkSimpleDialog.askstring("New File Name", "Fill in a new File Name") proj_path = os.path.join(self.settings.projects_path, self.settings.current_project) nfile_name = os.path.join(proj_path, nfile_name.strip()+'.txt') nfile = codecs.open(nfile_name, 'w', 'utf-8') current_project = self.settings.current_project infostring1 = u'# Diese Datei wurde automatisch mit ' infostring2 = u'dem Projekt "%s" erstellt' % current_project nfile.write(infostring1+infostring2 ) nfile.close() self.on_open(nfile_name) def on_del_page(self): """""" print "del page" # self.settings.current_project del_file = os.path.join(self.settings.projects_path, self.settings.current_project, self.opened_filename) del_page = askyesno("Do you really want to delete ", del_file) if del_page: #self.set_project(self.new_project_name) print "%s geloescht" % del_file os.remove(del_file) def on_tag_insert(self, event=None, open_tag=None, close_tag=None): """ inserts a (wiki)tag to the current cursor position. If there is no text marked in the editfield, open_tag and close_tag are inserted to the current cursor position behind each other and the cursor jumps in between. Otherwise the marked string is enclosed by open_tag and close_tag and inserted to the current cursor position. Here the new cursor position is right behind the complete inserted string with tags. At this moment this behavior is quite buggy :-( idea: - new parameter for on_tag_insert() jump_in_between=True/False so a pulldown list for different levels of headlines arn't necessary - rename to: on_insert_tag?? on_tag_insert Parameter: --> event # keyboard shortcut --> open_tag # string --> close_tag # string """ #print 'event',event #print 'open_tag',open_tag #print 'close_tag',close_tag ## when no String is selected: if not self.text.tag_ranges(tk.SEL): print "no String is selected" insert_point = self.text.index('insert') insertline = insert_point.split('.')[0] addit = 1 if event != None: print "event not None" addit = 2 insertrow = str(int(insert_point.split('.')[1])+len(open_tag)+addit) new_insert_point = insertline+'.'+ insertrow self.text.insert(insert_point, open_tag+''+close_tag) # place cursor to insert_point self.text.mark_set(tk.INSERT, new_insert_point) # display this position on the editfield self.text.see(tk.INSERT) ## when a String is selected: else: #print "im else" marked_text = self.text.get(self.text.index(tk.SEL_FIRST), self.text.index(tk.SEL_LAST)) replace_index = self.text.index(tk.SEL_FIRST) print "replace_index in selected", replace_index self.text.delete(self.text.index(tk.SEL_FIRST), self.text.index(tk.SEL_LAST)) self.text.insert(replace_index, open_tag+marked_text+close_tag)
class Tkui(base.BaseUI): """ This is a ui class which handles the complete Tk user interface. """ def __init__(self): """ Initializes.""" base.BaseUI.__init__(self) # internal ui queue self._event_queue = Queue.Queue() # map of session -> (bold, foreground, background) self._currcolors = {} # ses -> string self._unfinishedcolor = {} self._viewhistory = 0 self._do_i_echo = 1 # holds a map of window names -> window references self._windows = {} # instantiate all the widgets self._tk = Tk() self._tk.geometry("800x600") self.settitle() if os.name == 'posix': fnt = tkFont.Font(family="Courier", size=12) else: fnt = tkFont.Font(family="Fixedsys", size=12) self._entry = CommandEntry(self._tk, self, fg='white', bg='black', insertbackground='yellow', font=fnt, insertwidth='2') self._entry.pack(side='bottom', fill='both') self._topframe = Frame(self._tk) self._topframe.pack(side='top', fill='both', expand=1) self._txt = ScrolledText(self._topframe, fg='white', bg='black', font=fnt, height=20) self._txt.pack(side='bottom', fill='both', expand=1) self._txt.bind("<KeyPress>", self._ignoreThis) self._txtbuffer = ScrolledText(self._topframe, fg='white', bg='black', font=fnt, height=20) self._txtbuffer.bind("<KeyPress-Escape>", self.escape) self._txtbuffer.bind("<KeyPress>", self._ignoreThis) self._entry.focus_set() self._initColorTags() self.dequeue() exported.hook_register("config_change_hook", self.configChangeHandler) exported.hook_register("to_user_hook", self.write) # FIXME - fix this explanation. this is just terrible. tc = config.BoolConfig( "saveinputhighlight", 0, 1, "Allows you to change the behavior of the command entry. When " "saveinputhighlight is off, we discard whatever is on the entry " "line. When it is on, we will retain the contents allowing you " "to press the enter key to do whatever you typed again.") exported.add_config("saveinputhighlight", tc) self._quit = 0 def runui(self): global HELP_TEXT exported.add_help("tkui", HELP_TEXT) exported.write_message("For tk help type \"#help tkui\".") exported.add_command("colorcheck", colorcheck_cmd) # run the tk mainloop here self._tk.mainloop() def wantMainThread(self): # The tkui needs the main thread of execution so we return # a 1 here. return 1 def quit(self): if not self._quit: self._quit = 1 self._topframe.quit() def dequeue(self): qsize = self._event_queue.qsize() if qsize > 10: qsize = 10 for i in range(qsize): ev = self._event_queue.get_nowait() ev.execute(self) self._tk.after(25, self.dequeue) def settitle(self, title=""): """ Sets the title bar to the Lyntin title plus the given string. @param title: the title to set @type title: string """ if title: title = constants.LYNTINTITLE + title else: title = constants.LYNTINTITLE self._event_queue.put(_TitleEvent(self._tk, title)) def removeWindow(self, windowname): """ This removes a NamedWindow from our list of NamedWindows. @param windowname: the name of the window to write to @type windowname: string """ if self._windows.has_key(windowname): del self._windows[windowname] def writeWindow(self, windowname, message): """ This writes to the window named "windowname". If the window does not exist, we spin one off. It handles ansi text and messages just like writing to the main window. @param windowname: the name of the window to write to @type windowname: string @param message: the message to write to the window @type message: string or Message instance """ self._event_queue.put(_WriteWindowEvent(windowname, message)) def writeWindow_internal(self, windowname, message): if not self._windows.has_key(windowname): self._windows[windowname] = NamedWindow(windowname, self, self._tk) self._windows[windowname].write(message) def _ignoreThis(self, tkevent): """ This catches keypresses from the history buffer.""" # kludge so that ctrl-c doesn't get caught allowing windows # users to copy the buffer.... if tkevent.keycode == 17 or tkevent.keycode == 67: return self._entry.focus() if tkevent.char: # we do this little song and dance so as to pass events # we don't want to deal with to the entry widget essentially # by creating a new event and tossing it in the event list. # it only sort of works--but it's the best code we've got # so far. args = ('event', 'generate', self._entry, "<KeyPress>") args = args + ('-rootx', tkevent.x_root) args = args + ('-rooty', tkevent.y_root) args = args + ('-keycode', tkevent.keycode) args = args + ('-keysym', tkevent.keysym) self._tk.tk.call(args) return "break" def pageUp(self): """ Handles prior (Page-Up) events.""" if self._viewhistory == 0: self._txtbuffer.pack(side='top', fill='both', expand=1) self._viewhistory = 1 self._txtbuffer.delete("1.0", "end") lotofstuff = self._txt.get('1.0', 'end') self._txtbuffer.insert('end', lotofstuff) for t in self._txt.tag_names(): taux = None tst = 0 for e in self._txt.tag_ranges(t): if tst == 0: taux = e tst = 1 else: tst = 0 self._txtbuffer.tag_add(t, str(taux), str(e)) self._txtbuffer.yview('moveto', '1') if os.name != 'posix': self._txtbuffer.yview('scroll', '20', 'units') self._tk.update_idletasks() self._txt.yview('moveto', '1.0') if os.name != 'posix': self._txt.yview('scroll', '220', 'units') else: # yscroll up stuff self._txtbuffer.yview('scroll', '-15', 'units') def pageDown(self): """ Handles next (Page-Down) events.""" if self._viewhistory == 1: # yscroll down stuff self._txtbuffer.yview('scroll', '15', 'units') def escape(self, tkevent): """ Handles escape (Escape) events.""" if self._viewhistory == 1: self._txtbuffer.forget() self._viewhistory = 0 else: self._entry.clearInput() def configChangeHandler(self, args): """ This handles config changes including mudecho. """ name = args["name"] newvalue = args["newvalue"] if name == "mudecho": if newvalue == 1: # echo on self._do_i_echo = 1 self._entry.configure(show='') else: # echo off self._do_i_echo = 0 self._entry.configure(show='*') def _yadjust(self): """Handles y scrolling after text insertion.""" self._txt.yview('moveto', '1') # if os.name != 'posix': self._txt.yview('scroll', '20', 'units') def _clipText(self): """ Scrolls the text buffer up so that the new text written at the bottom of the text buffer can be seen. """ temp = self._txt.index("end") ind = temp.find(".") temp = temp[:ind] if (temp.isdigit() and int(temp) > 800): self._txt.delete("1.0", "100.end") def write(self, args): """ This writes text to the text buffer for viewing by the user. This is overridden from the 'base.BaseUI'. """ self._event_queue.put(_OutputEvent(args)) def write_internal(self, args): mess = args["message"] if type(mess) == types.StringType: mess = message.Message(mess, message.LTDATA) line = mess.data ses = mess.session if line == '' or self.showTextForSession(ses) == 0: return color, leftover = buffer_write(mess, self._txt, self._currcolors, self._unfinishedcolor) if mess.type == message.MUDDATA: self._unfinishedcolor[ses] = leftover self._currcolors[ses] = color self._clipText() self._yadjust() def convertColor(self, name): """ Tk has this really weird color palatte. So I switched to using color names in most cases and rgb values in cases where I couldn't find a good color name. This method allows me to specify either an rgb or a color name and it converts the color names to rgb. @param name: either an rgb value or a name @type name: string @returns: the rgb color value @rtype: string """ if name.startswith("#"): return name rgb = self._tk._getints( self._tk.tk.call('winfo', 'rgb', self._txt, name)) rgb = "#%02x%02x%02x" % (rgb[0] / 256, rgb[1] / 256, rgb[2] / 256) print name, "converted to: ", rgb return rgb def _initColorTags(self): """ Sets up Tk tags for the text widget (fg/bg/u).""" for ck in fg_color_codes.keys(): color = self.convertColor(fg_color_codes[ck]) self._txt.tag_config(ck, foreground=color) self._txtbuffer.tag_config(ck, foreground=color) for ck in bg_color_codes.keys(): self._txt.tag_config(ck, background=bg_color_codes[ck]) self._txtbuffer.tag_config(ck, background=bg_color_codes[ck]) self._txt.tag_config("u", underline=1) self._txtbuffer.tag_config("u", underline=1) def colorCheck(self): """ Goes through and displays all the combinations of fg and bg with the text string involved. Purely for debugging purposes. """ fgkeys = ['30', '31', '32', '33', '34', '35', '36', '37'] bgkeys = ['40', '41', '42', '43', '44', '45', '46', '47'] self._txt.insert('end', 'color check:\n') for bg in bgkeys: for fg in fgkeys: self._txt.insert('end', str(fg), (fg, bg)) self._txt.insert('end', str("b" + fg), ("b" + fg, bg)) self._txt.insert('end', '\n') for fg in fgkeys: self._txt.insert('end', str(fg), (fg, "b" + bg)) self._txt.insert('end', str("b" + fg), ("b" + fg, "b" + bg)) self._txt.insert('end', '\n') self._txt.insert('end', '\n') self._txt.insert('end', '\n')
class NamedWindow: """ This creates a window for the Tkui which you can then write to programmatically. This allows modules to spin off new named windows and write to them. """ def __init__(self, windowname, master, partk): """ Initializes the window @param windowname: the name of the new window @type windowname: string @param master: the main tk window @type master: toplevel """ self._parent = master self._tk = Toplevel(partk) self._windowname = windowname # map of session -> (bold, foreground, background) self._currcolors = {} # ses -> string self._unfinishedcolor = {} self._do_i_echo = 1 self._tk.geometry("500x300") self._tk.title("Lyntin -- " + self._windowname) self._tk.protocol("WM_DELETE_WINDOW", self.close) if os.name == "posix": fontname = "Courier" else: fontname = "Fixedsys" fnt = tkFont.Font(family=fontname, size=12) self._txt = ScrolledText(self._tk, fg="white", bg="black", font=fnt, height=20) self._txt.pack(side=TOP, fill=BOTH, expand=1) # handles improper keypresses self._txt.bind("<KeyPress>", self._ignoreThis) # initialize color tags self._initColorTags() def convertColor(self, name): """ Tk has this really weird color palatte. So I switched to using color names in most cases and rgb values in cases where I couldn't find a good color name. This method allows me to specify either an rgb or a color name and it converts the color names to rgb. @param name: either an rgb value or a name @type name: string @returns: the rgb color value @rtype: string """ if name[0] == "#": return name rgb = self._tk._getints(self._tk.tk.call("winfo", "rgb", self._txt, name)) rgb = "#%02x%02x%02x" % (rgb[0] / 256, rgb[1] / 256, rgb[2] / 256) print name, "converted to: ", rgb return rgb def _initColorTags(self): """ Sets up Tk tags for the text widget (fg/bg).""" for ck in fg_color_codes.keys(): color = self.convertColor(fg_color_codes[ck]) self._txt.tag_config(ck, foreground=color) for ck in bg_color_codes.keys(): self._txt.tag_config(ck, background=bg_color_codes[ck]) self._txt.tag_config("u", underline=1) def _ignoreThis(self, tkevent): """ This catches keypresses to this window. """ return "break" def close(self): """ Closes and destroys references to this window. """ self._parent.removeWindow(self._windowname) self._tk.destroy() def _yadjust(self): """Handles y scrolling after text insertion.""" self._txt.yview("moveto", "1") # if os.name != 'posix': self._txt.yview("scroll", "20", "units") def _clipText(self): """ Scrolls the text buffer up so that the new text written at the bottom of the text buffer can be seen. """ temp = self._txt.index("end") ind = temp.find(".") temp = temp[:ind] if temp.isdigit() and int(temp) > 800: self._txt.delete("1.0", "100.end") def write(self, msg): """ This writes text to the text buffer for viewing by the user. This is overridden from the 'base.BaseUI'. """ if type(msg) == types.TupleType: msg = msg[0] if type(msg) == types.StringType: msg = message.Message(msg, message.LTDATA) line = msg.data ses = msg.session if line == "": return color, leftover = buffer_write(msg, self._txt, self._currcolors, self._unfinishedcolor) if msg.type == message.MUDDATA: self._unfinishedcolor[ses] = leftover self._currcolors[ses] = color self._clipText() self._yadjust()
class NamedWindow: """ This creates a window for the Tkui which you can then write to programmatically. This allows modules to spin off new named windows and write to them. """ def __init__(self, windowname, master, partk): """ Initializes the window @param windowname: the name of the new window @type windowname: string @param master: the main tk window @type master: toplevel """ self._parent = master self._tk = Toplevel(partk) self._windowname = windowname # map of session -> (bold, foreground, background) self._currcolors = {} # ses -> string self._unfinishedcolor = {} self._do_i_echo = 1 self._tk.geometry("500x300") self._tk.title("Lyntin -- " + self._windowname) self._tk.protocol("WM_DELETE_WINDOW", self.close) if os.name == "posix": fontname = "Courier" else: fontname = "Fixedsys" fnt = tkFont.Font(family=fontname, size=12) self._txt = ScrolledText(self._tk, fg="white", bg="black", font=fnt, height=20) self._txt.pack(side=TOP, fill=BOTH, expand=1) # handles improper keypresses self._txt.bind("<KeyPress>", self._ignoreThis) # initialize color tags self._initColorTags() def convertColor(self, name): """ Tk has this really weird color palatte. So I switched to using color names in most cases and rgb values in cases where I couldn't find a good color name. This method allows me to specify either an rgb or a color name and it converts the color names to rgb. @param name: either an rgb value or a name @type name: string @returns: the rgb color value @rtype: string """ if name[0] == "#": return name rgb = self._tk._getints( self._tk.tk.call('winfo', 'rgb', self._txt, name)) rgb = "#%02x%02x%02x" % (rgb[0] / 256, rgb[1] / 256, rgb[2] / 256) print name, "converted to: ", rgb return rgb def _initColorTags(self): """ Sets up Tk tags for the text widget (fg/bg).""" for ck in fg_color_codes.keys(): color = self.convertColor(fg_color_codes[ck]) self._txt.tag_config(ck, foreground=color) for ck in bg_color_codes.keys(): self._txt.tag_config(ck, background=bg_color_codes[ck]) self._txt.tag_config("u", underline=1) def _ignoreThis(self, tkevent): """ This catches keypresses to this window. """ return "break" def close(self): """ Closes and destroys references to this window. """ self._parent.removeWindow(self._windowname) self._tk.destroy() def _yadjust(self): """Handles y scrolling after text insertion.""" self._txt.yview('moveto', '1') # if os.name != 'posix': self._txt.yview('scroll', '20', 'units') def _clipText(self): """ Scrolls the text buffer up so that the new text written at the bottom of the text buffer can be seen. """ temp = self._txt.index("end") ind = temp.find(".") temp = temp[:ind] if (temp.isdigit() and int(temp) > 800): self._txt.delete("1.0", "100.end") def write(self, msg): """ This writes text to the text buffer for viewing by the user. This is overridden from the 'base.BaseUI'. """ if type(msg) == types.TupleType: msg = msg[0] if type(msg) == types.StringType: msg = message.Message(msg, message.LTDATA) line = msg.data ses = msg.session if line == '': return color, leftover = buffer_write(msg, self._txt, self._currcolors, self._unfinishedcolor) if msg.type == message.MUDDATA: self._unfinishedcolor[ses] = leftover self._currcolors[ses] = color self._clipText() self._yadjust()
class myPanel(tkinter.Tk): def __init__(self): tkinter.Tk.__init__(self, 'lsx') try: self.ss = self.clipboard_get() except: self.ss = '' self.cnt = 0 self.slices = paragraph(self.ss, qrlen) self.string = None if not os.path.exists('config.ini'): x = - 100 + 0.2 * self.winfo_screenwidth() # 100: 补偿初始Tk界面为200x200 y = - 100 + 0.7 * self.winfo_screenheight() xy = '+%d+%d'%(x,y) with open('config.ini','w') as f: f.write(xy) with open('config.ini','r') as f: xy = f.read() self.geometry(xy) self.minsize(450,206) self.qrc = tkinter.Label(self) self.ent = ScrolledText(self, width=1, height=15) self.ent.insert(1.0, self.ss) self.ent.mark_set('insert','0.0') # 程序首次运行时不使用see函数,否则会有未知原因半行内容沉没在Text窗体上面一点点 self.ent.focus() text = self.slices[self.cnt] basic = (len(self.slices),len(self.ss)) info = 'Page: %s, Length: %s'%basic if zh_cn: info = '共%s页, %s字'%basic self.withdraw() # withdraw/deiconify 阻止页面闪烁 self.update_idletasks() self.ent.pack(padx=2, pady=2, fill='both', expand=True, side='right') # RIGHT为了在Label隐藏再显示后所在位置一致 self.qrc.pack() self.setQrcode(text, info) self.deiconify() self.qrc.bind('<Button-2>',self.onExit) self.qrc.bind('<Button-1>',self.fliping) self.qrc.bind('<Button-3>',self.fliping) self.qrc.bind('<Double-Button-1>',self.setting) self.qrc.bind('<Double-ButtonRelease-3>',self.openFile) # 没有Release会在窗口打开之后的鼠标抬起时唤起右键菜单 self.ent.bind('<Escape>',self.onExit) self.ent.bind('<F1>',self.openFile) self.ent.bind('<F2>',self.fliping) self.ent.bind('<F3>',self.fliping) self.ent.bind('<F4>',self.setting) self.ent.bind('<KeyRelease>',self.refresh) self.ent.bind('<ButtonRelease-1>',self.selected) self.bind('<Destroy>',lambda evt:self.onExit(evt,close=True)) def setQrcode(self, string, info): if self.string != string: self.string = string if string == '': self.qrc.forget() else: global img img = qrmake(string) self.qrc.config(image=img) self.qrc.pack() log(string, info) self.title('Text Helper v1.06 (%s)'%info) if zh_cn: self.title('文本助手v1.06 (%s)'%info) def refresh(self, evt): if evt.keysym in ['Control_L', 'Return', 'BackSpace']: ss2 = self.ent.get('0.0', 'end')[:-1] if self.ss != ss2: self.ss = ss2 self.cnt = 0 self.slices = paragraph(self.ss, qrlen) text = self.slices[self.cnt] basic = (len(self.slices),len(self.ss)) info = 'Page: %s, Length: %s'%basic if zh_cn: info = '共%s页, %s字'%basic self.setQrcode(text, info) def fliping(self, evt): if evt.num == 1 or evt.keysym == 'F3': self.cnt = min(self.cnt+1,len(self.slices)-1) else: self.cnt = max(self.cnt-1,0) cur1 = getIndex(''.join(self.slices[:self.cnt])) cur2 = getIndex(''.join(self.slices[:self.cnt+1])) self.setCursor(cur1, cur2) text = self.slices[self.cnt] basic = (self.cnt+1,len(self.slices),len(text),len(self.ss)) info = 'Page: %s/%s, Sel: %s/%s'%basic if zh_cn: info = '第%s/%s页, 共%s/%s字'%basic self.setQrcode(text, info) def selected(self, evt): if self.ent.tag_ranges('sel'): text = self.ent.selection_get() info = 'Sel: %s/%s'%(len(text),len(self.ss)) if zh_cn: info = '选中%s/%s字'%(len(text),len(self.ss)) self.setQrcode(text, info) def setCursor(self, cur1, cur2): self.ent.mark_set('insert', cur1) self.ent.tag_remove('sel','0.0','end') self.ent.tag_add('sel',cur1,cur2) self.ent.see(cur1) def setting(self, evt): max_page = len(self.slices) num = tkinter.simpledialog.askinteger('Goto','Go to page (1-%s):'%max_page, initialvalue=self.cnt+1) self.ent.focus() if num: self.cnt = max(1,min(max_page,num)) - 1 text = self.slices[self.cnt] basic = (self.cnt+1,len(self.slices),len(text),len(self.ss)) info = 'Page: %s/%s, Sel: %s/%s'%basic if zh_cn: info = '第%s/%s页, 共%s/%s字'%basic self.setQrcode(text, info) def openFile(self, evt): path = tkinter.filedialog.askopenfilename() if path != '': filename = os.path.basename(path) with open(path,'rb') as f: s = f.read() try: try: res = s.decode() except: try: res = s.decode('gbk') except: raise except: s = base64.urlsafe_b64encode(filename.encode()+b'\n'+s).decode() total = int((len(s)-1)/(qrlen-10)+1) res = '' for i in range(total): res += '%04d%04d.%s,'%(total, i+1, s[(qrlen-10)*i:(qrlen-10)*(i+1)]) self.ss = res self.cnt = 0 self.slices = paragraph(self.ss, qrlen) self.ent.delete(1.0, 'end') self.ent.insert(1.0, res) text = self.slices[self.cnt] basic = (len(self.slices),len(self.ss)) info = 'Page: %s, Length: %s'%basic if zh_cn: info = '共%s页, %s字'%basic self.setQrcode(text, info) def onExit(self, evt, close=False): xy = '+%d+%d'%(self.winfo_x(),self.winfo_y()) with open('config.ini','w') as f: f.write(xy) if not close: self.destroy()
import thread, Queue as queue, time dataQueue = queue.Queue() # infinite size def producer(id): for i in range(5): time.sleep(0.1) print('put') dataQueue.put('[producer id=%d, count=%d]' % (id, i)) def consumer(root): while not dataQueue.empty(): data = dataQueue.get(block=False) root.insert('end', 'consumer got => %s\n' % str(data)) root.see('end') root.after(250, lambda: consumer(root)) # 4 times per sec def makethreads(): for i in range(4): thread.start_new_thread(producer, (i,)) if __name__ == '__main__': # main GUI thread: spawn batch of worker threads on each mouse click from ScrolledText import ScrolledText root = ScrolledText() root.pack() root.bind('<Button-1>', lambda event: makethreads()) consumer(root) # start queue check loop in main thread root.mainloop() # pop-up window, enter tk event loop