コード例 #1
0
ファイル: chatclient.py プロジェクト: notopwn/supermoon1215
class ChatClient:
    client_socket = None

    def __init__(self, ip, port):
        self.initialize_socket(ip, port)
        self.initialize_gui()
        self.listen_thread()

    def initialize_socket(self, ip, port):
        self.client_socket = socket(AF_INET, SOCK_STREAM)
        remote_ip = ip
        remote_port = port
        self.client_socket.connect((remote_ip, remote_port))

    def send_chat(self):
        senders_name = self.name_widget.get().strip() + ":"
        data = self.enter_text_widget.get(1.0, 'end').strip()
        message = (senders_name + data).encode('utf-8')
        self.chat_transcript_area.insert('end', message.decode('utf-8') + '\n')
        self.chat_transcript_area.yview(END)
        self.client_socket.send(message)
        self.enter_text_widget.delete(1.0, 'end')
        return 'break'

    def initialize_gui(self):
        self.root = Tk()
        fr = []
        for i in range(0, 5):
            fr.append(Frame(self.root))
            fr[i].pack(fill=BOTH)

        self.name_label = Label(fr[0], text='username')
        self.recv_label = Label(fr[1], text='received message')
        self.send_label = Label(fr[3], text='sending message')
        self.send_btn = Button(fr[3], text='전송', command=self.send_chat)
        self.chat_transcript_area = ScrolledText(fr[2], height=20, width=60)
        self.enter_text_widget = ScrolledText(fr[4], height=5, width=60)
        self.name_widget = Entry(fr[0], width=15)

        self.name_label.pack(side=LEFT)
        self.name_widget.pack(side=LEFT)
        self.recv_label.pack(side=LEFT)
        self.send_btn.pack(side=RIGHT, padx=20)
        self.chat_transcript_area.pack(side=LEFT, padx=2, pady=2)
        self.send_label.pack(side=LEFT)
        self.enter_text_widget.pack(side=LEFT, padx=2, pady=2)

    def listen_thread(self):
        t = Thread(target=self.receive_message, args=(self.client_socket, ))
        t.start()

    def receive_message(self, so):
        while True:
            buf = so.recv(256)
            if not buf:
                break
                self.chat_transcript_area.insert('end',
                                                 buf.decode('utf-8') + '\n')
                self.chat_transcript_area.yview(END)
            so.close()
コード例 #2
0
ファイル: bfmain.py プロジェクト: wfzirk/Sun-Font-Utility
class ConsoleUi(logging.Handler):
    def __init__(self, parent, update_interval=50, process_lines=500):
        logging.Handler.__init__(self)

        self.update_interval = update_interval
        self.process_lines = process_lines
        self.parent = parent
        #self.after(self.update_interval, self.fetch_lines)
        
        # Create a ScrolledText wdiget
        self.scrolled_text = ScrolledText(self.parent, state='disabled', height=20)
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font='TkFixedFont')
        self.scrolled_text.tag_config('INFO', foreground='black')
        self.scrolled_text.tag_config('DEBUG', foreground='gray')
        self.scrolled_text.tag_config('WARNING', foreground='orangered')
        self.scrolled_text.tag_config('ERROR', foreground='red')
        self.scrolled_text.tag_config('CRITICAL', foreground='red', underline=1)
        self.scrolled_text.tag_config('OTHER', foreground='blue')
       
        #ConsoleUi.display = self.display
        ConsoleUi.displayText = self.displayText
        ConsoleUi.clearDisp = self.clearDisp

    def emit(self, record):
        msg = self.format(record)
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(tk.END, msg + '\n', record.levelname)
        self.scrolled_text.configure(state='disabled')
        # Autoscroll to the bottom
        self.scrolled_text.yview(tk.END)

    def clearDisp(self, *args):
        print('clearDisp')
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.delete(0.0, tk.END)
        self.scrolled_text.configure(state='disabled')
    
    def displayText(self, *args):       # for text files
        text = ' '.join([str(a) for a in args])
        print(text, end='')
        self.scrolled_text.configure(state='normal')
        if ' ERROR ' in text:
            tag = 'ERROR'
        elif ' DEBUG ' in text:
            tag = 'DEBUG'
        elif ' INFO ' in text:
            tag = 'INFO'
        elif ' WARNING ' in text:
            tag = 'WARNING'
        elif ' CRITICAL ' in text:
            tag = 'CRITICAL'
        else:
            tag = 'OTHER'
            text = text+'\n'    
        self.scrolled_text.insert(tk.END, text, tag)
        self.scrolled_text.configure(state='disabled')
        # Autoscroll to the bottom
        self.scrolled_text.yview(tk.END)
        self.scrolled_text.update_idletasks()
コード例 #3
0
class ChatClient:
    #    sock = None

    def __init__(self, ip, port):
        self.sock = socket(AF_INET, SOCK_STREAM)
        self.sock.connect((ip, port))
        self.initialize_gui()
        self.receiving_thread()

    def initialize_gui(self):
        # widget 배치 및 초기화
        self.root = Tk()
        fr = []
        for i in range(0, 5):
            fr.append(Frame(self.root))
            fr[i].pack(fill=BOTH)

        self.name_label = Label(fr[0], text='사용자 이름')
        self.recv_label = Label(fr[1], text='수신 메시지 : ')
        self.send_label = Label(fr[3], text='송신 메시지 : ')
        self.send_btn = Button(fr[3], text='전송', command=self.send_chat)
        self.quit_btn = Button(fr[3], text='종료', command=self.root.quit)
        self.chat_transcript_area = ScrolledText(fr[2], height=20, width=60)
        self.enter_text_widget = ScrolledText(fr[4], height=5, width=60)
        self.name_widget = Entry(fr[0], width=15)

        self.name_label.pack(side=LEFT)
        self.name_widget.pack(side=LEFT)
        self.recv_label.pack(side=LEFT)
        self.send_btn.pack(side=RIGHT, padx=40)
        self.quit_btn.pack(side=RIGHT, padx=20)
        self.chat_transcript_area.pack(side=LEFT, padx=2, pady=2)
        self.send_label.pack(side=LEFT)
        self.enter_text_widget.pack(side=LEFT, padx=2, pady=2)

    def send_chat(self):
        # 메세지 전송하는 콜백함수
        sender_name = self.name_widget.get().strip() + ':'
        data = self.enter_text_widget.get(1.0, 'end').strip()
        message = (sender_name + data).encode('utf-8')
        self.chat_transcript_area.insert('end', message.decode('utf-8') + '\n')
        self.chat_transcript_area.yview(END)
        self.sock.send(message)
        self.enter_text_widget.delete(1.0, 'end')
        return 'break'

    def receiving_thread(self):
        # 데이터 수신 Thread 생성, 시작
        t = Thread(target=self.receive_message, args=(self.sock, ))
        t.start()

    def receive_message(self, sock):
        while True:
            buf = sock.recv(256)
            if not buf:
                break
            self.chat_transcript_area.insert('end', buf.decode('utf-8') + '\n')
            self.chat_transcript_area.yview(END)
        socket.close()
コード例 #4
0
ファイル: console_ui.py プロジェクト: TobyBoyne/py-toolkit
class ConsoleUi:
	"""Poll messages from a logging queue and display them in a scrolled text widget"""
	def __init__(self, frame):
		self.frame = frame
		self.input_start_idx = tk.END
		# Create a ScrolledText wdiget
		self.scrolled_text = ScrolledText(frame, state='disabled', height=12)
		self.scrolled_text.pack(expand=True, fill=tk.BOTH)
		self.scrolled_text.configure(font='TkFixedFont')
		self.scrolled_text.tag_config('INFO',     foreground='black')
		self.scrolled_text.tag_config('DEBUG',    foreground='gray')
		self.scrolled_text.tag_config('WARNING',  foreground='dark orange')
		self.scrolled_text.tag_config('ERROR',    foreground='red')
		self.scrolled_text.tag_config('CRITICAL', foreground='red', underline=1)

		self.scrolled_text.bind('<Key>', self.key_press)

		# Create a logging handler using a queue
		self.log_queue = queue.Queue()
		self.queue_handler = QueueHandler(self.log_queue)
		formatter = logging.Formatter('%(asctime)s:\t%(message)s', datefmt='%H:%M:%S')
		self.queue_handler.setFormatter(formatter)
		logger.addHandler(self.queue_handler)
		# Start polling messages from the queue
		self.frame.after(100, self.poll_log_queue)

	def display(self, record):
		msg = record.getMessage()
		self.scrolled_text.configure(state='normal')
		self.scrolled_text.insert(tk.END, msg + '\n', record.levelname)
		# self.scrolled_text.configure(state='disabled')
		# Autoscroll to the bottom
		self.scrolled_text.yview(tk.END)

		self.scrolled_text.mark_set('input_start', 'end-1c')
		self.scrolled_text.mark_gravity('input_start', tk.LEFT)

	def poll_log_queue(self):
		while True:
			try:
				record = self.log_queue.get(block=False)
			except queue.Empty:
				break
			else:
				self.display(record)

		# Check every 100ms if there is a new message in the queue to display
		self.frame.after(100, self.poll_log_queue)

	def key_press(self, event):
		"""Function used to send any inputs to the input_queue when the return key is pressed"""
		if event.char == '\r':
			user_input = self.scrolled_text.get('input_start', 'end-1c').strip()
			input_queue.put(user_input)
			self.scrolled_text.mark_set('input_start', 'end-1c')
コード例 #5
0
ファイル: gui.py プロジェクト: nobbynobbs/async-python-5
async def update_conversation_history(panel: ScrolledText, messages_queue):
    while True:
        msg = await messages_queue.get()

        panel['state'] = 'normal'
        if panel.index('end-1c') != '1.0':
            panel.insert('end', '\n')
        panel.insert('end', msg)
        if panel.vbar.get()[1] == 1.0:
            panel.yview(tk.END)
        panel['state'] = 'disabled'
コード例 #6
0
class ConsoleUi:
    """Poll messages from a logging queue and display them in a scrolled text widget."""

    def __init__(self, frame, simple_time=False):
        self.frame = frame
        # Create a ScrolledText wdiget
        if simple_time:
            font='80'
        else:
            font=''
        self.scrolled_text = ScrolledText(frame, state='disabled', height=39)
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font='TkFixedFont')
        self.scrolled_text.tag_config('INFO', foreground='black', font=font)
        self.scrolled_text.tag_config('DEBUG', foreground='gray', font=font)
        self.scrolled_text.tag_config('WARNING', foreground='orange', font=font)
        self.scrolled_text.tag_config('ERROR', foreground='red', font=font)
        self.scrolled_text.tag_config('CRITICAL', foreground='red', underline=1, font=font)
        # Create a logging handler using a queue
        self.log_queue = Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        formatter = logging.Formatter('%(asctime)s: %(message)s')
        if simple_time is True:
            formatter = logging.Formatter("%(asctime)s: %(message)s", "%H:%M:%S")
        self.queue_handler.setFormatter(formatter)
        logger.addHandler(self.queue_handler)
        # Start polling messages from the queue
        self.frame.after(100, self.poll_log_queue)

    def display(self, record):
        msg = self.queue_handler.format(record)
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(tk.END, msg + '\n', record.levelname)
        self.scrolled_text.configure(state='disabled')
        # Autoscroll to the bottom
        self.scrolled_text.yview(tk.END)

    def poll_log_queue(self):
        # Check every 100ms if there is a new message in the queue to display
        while True:
            try:
                record = self.log_queue.get(block=False)
            except Queue_Empty:
                break
            else:
                self.display(record)
        self.frame.after(100, self.poll_log_queue)

    def pass_logger(self, in_logger):
        in_logger.addHandler(self.queue_handler)

    def set_levels(self, levels):
        self.queue_handler.addFilter(MyFilter(levels))
コード例 #7
0
class LoggingWindow:
    # Based on: https://github.com/beenje/tkinter-logging-text-widget
    def __init__(self, master):
        self.master = master
        self.scrolled_text = ScrolledText(master=master,
                                          state='disabled',
                                          height=15)
        self.scrolled_text.grid(row=0, column=0)
        self.scrolled_text.configure(font='TkFixedFont')
        self.scrolled_text.tag_config('INFO', foreground='black')
        self.scrolled_text.tag_config('DEBUG', foreground='gray')
        self.scrolled_text.tag_config('WARNING', foreground='orange')
        self.scrolled_text.tag_config('ERROR', foreground='red')

        # Get the logger
        self.logger = logging.getLogger()

        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        formatter = logging.Formatter(
            '%(asctime)s : %(levelname)s : %(message)s')
        self.queue_handler.setFormatter(formatter)
        self.logger.addHandler(self.queue_handler)
        # Start polling messages from the queue
        self.master.after(100, self.poll_log_queue)

        self.autoscroll = tk.BooleanVar()
        tk.Checkbutton(master, text='Autoscroll Log', variable=self.autoscroll).\
            grid(row=1, column=0, sticky=tk.W)
        self.autoscroll.set(True)

    def display(self, record):
        msg = self.queue_handler.format(record)
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(tk.END, msg + '\n', record.levelname)
        self.scrolled_text.configure(state='disabled')
        # Autoscroll to the bottom
        if self.autoscroll.get():
            self.scrolled_text.yview(tk.END)

    def poll_log_queue(self):
        # Check every 100ms if there is a new message in the queue to display
        while True:
            try:
                record = self.log_queue.get(block=False)
            except queue.Empty:
                break
            else:
                self.display(record)
        self.master.after(100, self.poll_log_queue)
コード例 #8
0
class ConsoleUi:
    """Poll messages from a logging queue and display them in a scrolled text widget"""
    def __init__(self, frame):
        self.frame = frame
        # Create a ScrolledText wdiget
        self.scrolled_text = ScrolledText(frame, state='disabled', height=12)
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font='TkFixedFont')
        self.scrolled_text.tag_config('INFO',
                                      foreground='white',
                                      background='green')
        self.scrolled_text.tag_config('DEBUG', foreground='gray')
        self.scrolled_text.tag_config('WARNING',
                                      foreground='yellow',
                                      background='purple')
        self.scrolled_text.tag_config('ERROR',
                                      foreground='black',
                                      background='yellow')
        self.scrolled_text.tag_config('CRITICAL',
                                      foreground='white',
                                      background='red',
                                      underline=1)
        # Create a logging handler using a queue
        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        formatter = logging.Formatter('%(asctime)s: %(message)s',
                                      "%d-%m %H:%M")
        self.queue_handler.setFormatter(formatter)
        logger.addHandler(self.queue_handler)
        # Start polling messages from the queue
        self.frame.after(100, self.poll_log_queue)

    def display(self, record):
        msg = self.queue_handler.format(record)
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(tk.END, msg + '\n', record.levelname)
        self.scrolled_text.configure(state='disabled')
        # Autoscroll to the bottom
        self.scrolled_text.yview(tk.END)

    def poll_log_queue(self):
        # Check every 100ms if there is a new message in the queue to display
        while True:
            try:
                record = self.log_queue.get(block=False)
            except queue.Empty:
                break
            else:
                self.display(record)
        self.frame.after(100, self.poll_log_queue)
コード例 #9
0
class ConsoleUi:
    """Poll messages from a logging queue and display them in a scrolled text widget"""
    def __init__(self, frame, master):
        self.frame = frame
        # Create a ScrolledText wdiget
        self.scrolled_text = ScrolledText(frame, state='disabled', height=12)
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font='TkFixedFont')
        self.scrolled_text.tag_config('INFO', foreground='black')
        self.scrolled_text.tag_config('DEBUG', foreground='gray')
        self.scrolled_text.tag_config('WARNING', foreground='orange')
        self.scrolled_text.tag_config('ERROR', foreground='red')
        self.scrolled_text.tag_config('CRITICAL',
                                      foreground='red',
                                      underline=1)
        # Create a logging handler using a queue
        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        formatter = logging.Formatter('%(message)s')
        self.queue_handler.setFormatter(formatter)
        logger.addHandler(self.queue_handler)
        # Start polling messages from the queue
        self.frame.after(100, self.poll_log_queue)
        self.scrolled_text.pack(fill=BOTH, expand=1)
        self.button_quit = Button(self.frame,
                                  text="Quit",
                                  fg="red",
                                  command=master.quit)
        self.button_quit.pack(anchor=NE, side=RIGHT)

    def display(self, record):
        msg = self.queue_handler.format(record)
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(END, msg + '\n', record.levelname)
        self.scrolled_text.configure(state='disabled')
        # Autoscroll to the bottom
        self.scrolled_text.yview(END)

    def poll_log_queue(self):
        # Check every 100ms if there is a new message in the queue to display
        while True:
            try:
                record = self.log_queue.get(block=False)
            except queue.Empty:
                break
            else:
                self.display(record)
        self.frame.after(100, self.poll_log_queue)
コード例 #10
0
ファイル: widgets.py プロジェクト: goofy0530/modlunky2
class ConsoleWindow(tk.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Create a ScrolledText wdiget
        self.scrolled_text = ScrolledText(self, height=7, state="disabled")
        self.scrolled_text.pack(expand=True, fill="both")
        self.scrolled_text.configure(font="TkFixedFont")
        self.scrolled_text.tag_config("INFO", foreground="green")
        self.scrolled_text.tag_config("DEBUG", foreground="gray")
        self.scrolled_text.tag_config("WARNING", foreground="orange")
        self.scrolled_text.tag_config("ERROR", foreground="red")
        self.scrolled_text.tag_config("CRITICAL",
                                      foreground="red",
                                      underline=1)

        # Create a logging handler using a queue
        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        formatter = logging.Formatter("%(asctime)s: %(message)s")
        self.queue_handler.setFormatter(formatter)
        logger.addHandler(self.queue_handler)

        # Start polling messages from the queue
        self.after(100, self.poll_log_queue)

    def display(self, record):
        msg = self.queue_handler.format(record)
        self.scrolled_text.configure(state="normal")
        self.scrolled_text.insert(tk.END, msg + "\n", record.levelname)
        self.scrolled_text.configure(state="disabled")
        self.scrolled_text.yview(tk.END)

    def poll_log_queue(self):
        # Check every 100ms if there is a new message in the queue to display
        while True:
            try:
                record = self.log_queue.get(block=False)
            except queue.Empty:
                break
            else:
                self.display(record)
        self.after(100, self.poll_log_queue)

    def close(self):
        pass
コード例 #11
0
class ConsoleLog:
    def __init__(self, frame):
        self.frame = frame
        self.scrolled_text = ScrolledText(self.frame,
                                          height=10,
                                          state="disabled",
                                          bg="dodger blue")
        self.scrolled_text.grid(row=0, columnspan=6)
        self.scrolled_text.configure(font="tkFixedFont", state="normal")
        self.scrolled_text.tag_config("INFO", foreground="black")
        self.scrolled_text.tag_config("WARNING", foreground="OrangeRed4")
        self.scrolled_text.tag_config("DEBUG", foreground='purple4')
        self.scrolled_text.tag_config("ERROR", foreground='red')
        self.scrolled_text.tag_config("CRITICAL",
                                      foreground="red4",
                                      underline="1")
        # Create a loggin handler using a queue
        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        formatter = logging.Formatter('%(asctime)s: %(message)s',
                                      datefmt="%I:%M:%S %p")
        self.queue_handler.setFormatter(formatter)
        logger.addHandler(self.queue_handler)
        self.frame.after(100, self.poll_log_queue)

    def display_log(self, record):
        msg = self.queue_handler.format(record)
        self.scrolled_text.configure(state="normal")
        self.scrolled_text.insert(END, msg + '\n', record.levelname)
        self.scrolled_text.configure(state="disabled")
        # autoscroll to bottom
        self.scrolled_text.yview(END)

    def poll_log_queue(self):
        # Check every 100ms if there is a new message to display in the queue
        while True:
            try:
                record = self.log_queue.get(block=False)
            except queue.Empty:
                break
            else:
                print(record)
                self.display_log(record)

        self.frame.after(100, self.poll_log_queue)
コード例 #12
0
class ConsoleUi:
    """Poll messages from a logging queue and display them in a scrolled text widget"""
    def __init__(self, frame):
        self.frame = frame
        # Create a ScrolledText wdiget
        self.scrolled_text = ScrolledText(frame, state="disabled", height=12)
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font="TkFixedFont")
        self.scrolled_text.tag_config("INFO", foreground="black")
        self.scrolled_text.tag_config("DEBUG", foreground="gray")
        self.scrolled_text.tag_config("WARNING", foreground="orange")
        self.scrolled_text.tag_config("ERROR", foreground="red")
        self.scrolled_text.tag_config("CRITICAL",
                                      foreground="red",
                                      underline=1)
        # Create a logging handler using a queue
        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        formatter = logging.Formatter("%(asctime)s: %(message)s")
        self.queue_handler.setFormatter(formatter)
        logger.addHandler(self.queue_handler)
        # Start polling messages from the queue
        self.frame.after(100, self.poll_log_queue)

    def display(self, record):
        msg = self.queue_handler.format(record)
        self.scrolled_text.configure(state="normal")
        self.scrolled_text.insert(tk.END, msg + "\n", record.levelname)
        self.scrolled_text.configure(state="disabled")
        # Autoscroll to the bottom
        self.scrolled_text.yview(tk.END)

    def poll_log_queue(self):
        # Check every 100ms if there is a new message in the queue to display
        while True:
            try:
                record = self.log_queue.get(block=False)
            except queue.Empty:
                break
            else:
                self.display(record)
        self.frame.after(100, self.poll_log_queue)
コード例 #13
0
class ConsoleUi:
    """Poll messages from a logging queue and display them in a scrolled text widget"""
    def __init__(self, frame):
        self.frame = frame
        # Create a ScrolledText wdiget
        self.scrolled_text = ScrolledText(frame, state='disabled', height=12)
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font='TkFixedFont')
        self.scrolled_text.tag_config('INFO', foreground='black')
        self.scrolled_text.tag_config('DEBUG', foreground='gray')
        self.scrolled_text.tag_config('WARNING', foreground='orange')
        self.scrolled_text.tag_config('ERROR', foreground='red')
        self.scrolled_text.tag_config('CRITICAL',
                                      foreground='red',
                                      underline=1)
        # Create a logging handler using a queue
        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        # Start polling messages from the queue
        self.frame.after(100, self.poll_log_queue)

    def display(self):
        msg = self.queue_handler
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(tk.END, msg + '\n')
        self.scrolled_text.configure(state='disabled')
        # Autoscroll to the bottom
        self.scrolled_text.yview(tk.END)

    def poll_log_queue(self):
        print("checked")
        # Check every 100ms if there is a new message in the queue to display
        while True:
            try:
                print("OOOOOOOOOin", queue.Empty())
                record = self.log_queue.get(block=False)
            except queue.Empty:
                break
            else:
                self.display()
        self.frame.after(100, self.poll_log_queue)
コード例 #14
0
ファイル: 123.py プロジェクト: yydderf/CommLab
class Log:
    def __init__(self, frame):
        self.frame = frame
        self.scrolled_text = ScrolledText(frame, state="disabled", height=23)
        # sticky -> what to do if the cell is larger than widget
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font="TkFixedFont")
        # queue -> logging handler
        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        logger.addHandler(self.queue_handler)
        # msg --> formatted_msg
        formatter = logging.Formatter(fmt='%(asctime)s: %(message)s',
                                      datefmt="%H:%M:%S")
        self.queue_handler.setFormatter(formatter)
        # start checking queue
        self.frame.after(0, self.check_queue)

    def push(self, text):
        # pushing messages into the frame
        msg = self.queue_handler.format(text)
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(END, msg + '\n')
        self.scrolled_text.configure(state='disabled')
        self.scrolled_text.yview(END)

    # check queue constantly
    def check_queue(self):
        while True:
            try:
                text = self.log_queue.get(
                    block=False)  # block=False --> don't wait for items
            except queue.Empty:
                break
            else:
                self.push(
                    text
                )  # push the text to the frame if the queue was not empty
        # check queue under 100ms frequency(human reaction 200~250ms)
        self.frame.after(100, self.check_queue)
コード例 #15
0
class Log:
    def __init__(self, frame):
        self.frame = frame

        self.scrolled_text = ScrolledText(frame, state="disabled", height=12)
        # sticky -> what to do if the cell is larger than widget
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font="TkFixedFont")
        # queue -> logging handler
        self.log_queue = queue.Queue()
        self.queue_handler = QueueHandler(self.log_queue)
        logger.addHandler(self.queue_handler)
        # msg --> formatted_msg
        formatter = logging.Formatter('%(asctime)s: %(message)s')
        self.queue_handler.setFormatter(formatter)
        # start checking queue
        self.frame.after(0, self.check_queue)

    def push(self, text):
        # pushing messages into the frame
        msg = self.queue_handler.format(text)
        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(END, msg+'\n')
        self.scrolled_text.configure(state='disabled')
        self.scrolled_text.yview(END)

    def check_queue(self):
        # check queue under 500ms frequency
        while True:
            try:
                text = self.log_queue.get(block=False)
            except queue.Empty:
                break
            else:
                self.push(text)
        self.frame.after(500, self.check_queue)
コード例 #16
0
ファイル: blocks.py プロジェクト: pohmelie/idev
class Logger(Frame):

    ERROR, BORRING, EVENT, NORMAL = "error", "borring", "event", None

    def __init__(self, *args, **kw):
        text_height = kw.pop("text_height", 25)

        Frame.__init__(self, *args, **kw)

        self.deque = deque()

        self.txt = ScrolledText(self, wrap=WORD, state=DISABLED, relief=SUNKEN, height=text_height)
        self.txt.grid(column=0, row=0, sticky=(N, W, E, S))
        self.txt.configure(LoggerColors.default)
        for k, v in LoggerColors.tags.items():
            self.txt.tag_configure(k, v)

        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)
        self.after(100, self._toscreen)

    def __call__(self, *args):
        self.deque.appendleft(args)

    def _toscreen(self):
        if len(self.deque):
            self.txt["state"] = NORMAL
            while(len(self.deque)):
                self.txt.insert(
                    END,
                    "\n[{}] ".format(strftime("%H:%M:%S")),
                    "time",
                    *self.deque.pop())
            self.txt.yview(END)
            self.txt["state"] = DISABLED
        self.after(100, self._toscreen)
コード例 #17
0
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()

        fnt = tkinter.font.Font(family="FixedSys", size=10)

        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 windowname in self._windows:
            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 windowname not in self._windows:
            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) == bytes:
            mess = message.Message(mess, message.LTDATA)
        elif "window" in mess.hints:
            self.writeWindow_internal(mess.hints["window"], mess)
            return

        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" % (old_div(rgb[0], 256), old_div(
            rgb[1], 256), old_div(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 list(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 list(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')
コード例 #18
0
ファイル: ser2.py プロジェクト: Ericean/Python
class GuiPart:
    def __init__(self, master, queue,queue2,queue3,endCommand):
        self.first_click = True;
        self.prefix1='Server says:'#Add the prefix for good display
        self.prefix2='Client says:'
        #Cause tkinter is not safe in thread, So use queue 
        #The Python Queue class has been specifically designed to be thread-safe
        #in a multi-producer, multi-consumer environment. 
        self.queue1 = queue 
        self.queue2 = queue2
        self.queue3 = queue3
        # Set up the GUI
        master.wm_title("Chat Server")
        master.resizable('1','1')
        
        self.ui_messages = ScrolledText(
            master=master,
            wrap=tkinter.WORD,
            width=50,  # In chars
            height=25)  # In chars     

        self.ui_input = tkinter.Text(
            master=master,
            wrap=tkinter.WORD,
            width=50,
            height=4)
        
        # Bind the button-1 click of the Entry to the handler
        self.ui_input.bind('<Button-1>', self.eventInputClick)
        
        self.ui_button_send = tkinter.Button(
            master=master,
            text="Send",
            command=self.sendMsg)

        self.ui_button_file = tkinter.Button(
            master=master,
            text="File",
            command=self.sendFile)

        # Compute display position for all objects
        self.ui_messages.pack(side=tkinter.TOP, fill=tkinter.BOTH)
        self.ui_input.pack(side=tkinter.TOP, fill=tkinter.BOTH)
        self.ui_button_send.pack(side=tkinter.LEFT)
        self.ui_button_file.pack(side=tkinter.RIGHT)
        # Add more GUI stuff here
        print("Starting serverUI...")
        self.ui_messages.insert(tkinter.END, "Adding a message to the text field...\n")
        self.ui_input.insert(tkinter.END, "<Enter message>")
       
    def processIncoming(self):
        """
        Handle all the messages currently in the queue (if any).
        """
        while self.queue1.qsize():
            try:
                msg = self.queue1.get(0)
                # Check contents of message and do what it says
                # As a test, we simply print it
                print (msg)
                self.ui_messages.insert(tkinter.INSERT, "%s\n" % (self.prefix2+msg))
                self.ui_messages.yview(tkinter.END)  # Auto-scrolling

            except Queue.Empty:
                pass
    # SEND button pressed
    def sendMsg(self):
        # Get user input (minus newline character at end)
        msg = self.ui_input.get("0.0", tkinter.END+"-1c")

        print("UI: Got text: '%s'" % msg)
        
        # Add this data to the message window
        if msg:
            self.ui_messages.insert(tkinter.INSERT, "%s\n" % (self.prefix1+msg))
            self.ui_messages.yview(tkinter.END)  # Auto-scrolling
            
            # Clean out input field for new data
            self.ui_input.delete("0.0", tkinter.END)
            self.registerEvent(self.queue2,msg)
            print("Test: Got text: '%s'" % msg)

    def registerEvent(self,container,msg):
        container.put(msg)


    # FILE button pressed
    def sendFile(self):
        file = askopenfilename()

        if(len(file) > 0 and os.path.isfile(file)):
            print("UI: Selected file: %s" % file)
        else:
            print("UI: File operation canceled")
        self.registerEvent(self.queue3,file)

        
    def eventInputClick(self, event):
        if(self.first_click):
            # If this is the first time the user clicked,
            # clear out the tutorial message currently in the box.
            # Otherwise, ignore it.
            self.ui_input.delete("0.0", tkinter.END)
            self.first_click = False;
コード例 #19
0
class GUI:
    """Graphical user interface to clfit.

    Data attributes that may sensibly be used externally:

    exe (string) -- path to clfit executable

    device (string) -- PGPLOT device, passed to clfit

    fileName (tkinter.StringVar) -- path to OI-FITS/Mapping Data file
    (use set() & get() methods)

    ChangeFileButton (tkinter.Button) -- brings up data file dialog
    box (may wish to disable)

    initialdir (string) -- initial directory for file dialog boxes

    preFitCallback -- function to call just before running clfit. If this
    returns false, clfit won't be run

    postFitCallback -- function to call after running clfit (if successful)

    """

    def __init__(self, parent, dismissCommand=None):
        """Constructor.

        Arguments are:

        parent -- parent window

        dismissCommand -- function to call when Dismiss button clicked

        """
        # Initialise data attributes
        self.parent = parent
        self.exe = "clfit"
        self.device = "/xserv"
        self.fileName = tk.StringVar()
        self.fileName.set("(unset)")
        self.initialdir = os.getcwd()
        self.preFitCallback = None
        self.postFitCallback = None
        self.calErr = tk.StringVar()
        self.calErr.set("0.0")
        self.cwl = tk.StringVar()
        self.bw = tk.StringVar()
        self.wlmin = tk.StringVar()
        self.wlmax = tk.StringVar()
        self.target_id = tk.StringVar()
        self.nofit = tk.IntVar()
        self.nofit.set(0)
        self.plots = [
            "No plot",
            "uv",
            "vis2",
            "t3amp",
            "t3phi",
            "vis2-wl",
            "t3amp-wl",
            "t3phi-wl",
            "vis2-mjd",
            "t3amp-mjd",
            "t3phi-mjd",
            "vis2-st",
            "t3amp-st",
            "t3phi-st",
            "vis2-pa",
            "post",
            "mpost",
            "post2d",
            "mpost2d",
        ]
        self.selPlot = tk.StringVar()
        self.selPlot.set(self.plots[1])
        self.plotXIndex = tk.StringVar()
        self.plotXIndex.set("1")
        self.plotYIndex = tk.StringVar()
        self.plotYIndex.set("2")
        self.plotXFrom = tk.StringVar()
        self.plotXTo = tk.StringVar()
        self.plotYFrom = tk.StringVar()
        self.plotYTo = tk.StringVar()
        self.margErr = tk.IntVar()
        self.margErr.set(0)
        self.margErrVar = tk.StringVar()
        self.margErrVar.set("1")

        # Initialise GUI elements
        fileFrame = tk.Frame(parent)
        fileFrame.pack(side=tk.TOP)
        tk.Label(fileFrame, text="Data file:").pack(side=tk.LEFT)
        tk.Label(fileFrame, textvariable=self.fileName).pack(side=tk.LEFT)
        self.ChangeFileButton = tk.Button(
            fileFrame, text="Change", command=self._ChangeFileName
        )
        self.ChangeFileButton.pack(side=tk.LEFT)
        calErrFrame = tk.Frame(parent)
        calErrFrame.pack(side=tk.TOP, fill=tk.X, pady=4)
        tk.Label(
            calErrFrame, text="Calibration Error (extra frac. error in system vis.)"
        ).pack(side=tk.LEFT, anchor=tk.W)
        tk.Entry(calErrFrame, textvariable=self.calErr, width=5).pack(
            side=tk.LEFT, anchor=tk.W, padx=4
        )
        wbFrame = tk.Frame(parent)
        wbFrame.pack(side=tk.TOP, fill=tk.X, pady=4)
        tk.Label(wbFrame, text="Waveband:").pack(side=tk.LEFT, anchor=tk.W)
        tk.Entry(wbFrame, textvariable=self.cwl, width=5).pack(
            side=tk.LEFT, anchor=tk.W, padx=4
        )
        tk.Entry(wbFrame, textvariable=self.bw, width=5).pack(
            side=tk.LEFT, anchor=tk.W, padx=4
        )
        tk.Label(wbFrame, text="or Wavelength range:").pack(side=tk.LEFT, anchor=tk.W)
        tk.Entry(wbFrame, textvariable=self.wlmin, width=5).pack(
            side=tk.LEFT, anchor=tk.W, padx=4
        )
        tk.Entry(wbFrame, textvariable=self.wlmax, width=5).pack(
            side=tk.LEFT, anchor=tk.W, padx=4
        )
        targetFrame = tk.Frame(parent)
        targetFrame.pack(side=tk.TOP, fill=tk.X, pady=4)
        tk.Label(
            targetFrame, text="TARGET_ID (blank to use 1st in OI_TARGET table):"
        ).pack(side=tk.LEFT, anchor=tk.W)
        tk.Entry(targetFrame, textvariable=self.target_id, width=5).pack(
            side=tk.LEFT, anchor=tk.W, padx=4
        )
        tk.Label(parent, text="Model:").pack(side=tk.TOP, anchor=tk.W)
        self.ModelText = ScrolledText(
            parent, height=19, width=40, font=("Helvetica", 10)
        )
        self.ModelText.pack(side=tk.TOP, expand=1, fill=tk.BOTH)
        midFrame1 = tk.Frame(parent)
        midFrame1.pack(side=tk.TOP, fill=tk.X, pady=4)
        tk.Label(midFrame1, text="Plot:").pack(side=tk.LEFT, anchor=tk.NW)
        plotFrame = tk.Frame(midFrame1)
        plotFrame.pack(side=tk.LEFT)
        ncol = 3
        for i in range(len(self.plots)):
            p = self.plots[i]
            tk.Radiobutton(plotFrame, text=p, variable=self.selPlot, value=p).grid(
                row=int((i + 1) / ncol), column=(i + 1) % ncol, sticky=tk.W
            )
        tk.Entry(plotFrame, textvariable=self.plotXIndex, width=3).grid(
            row=int(len(self.plots) / ncol) - 1, column=ncol
        )
        tk.Entry(plotFrame, textvariable=self.plotYIndex, width=3).grid(
            row=int(len(self.plots) / ncol), column=ncol
        )
        rangeFrame = tk.Frame(midFrame1)
        rangeFrame.pack(side=tk.LEFT)
        tk.Label(rangeFrame, text="X From:").grid(row=0, column=0, sticky=tk.E)
        tk.Entry(rangeFrame, textvariable=self.plotXFrom, width=5).grid(row=0, column=1)
        tk.Label(rangeFrame, text="To:").grid(row=0, column=2)
        tk.Entry(rangeFrame, textvariable=self.plotXTo, width=5).grid(row=0, column=3)
        tk.Label(rangeFrame, text="Y From:").grid(row=1, column=0, sticky=tk.E)
        tk.Entry(rangeFrame, textvariable=self.plotYFrom, width=5).grid(row=1, column=1)
        tk.Label(rangeFrame, text="To:").grid(row=1, column=2)
        tk.Entry(rangeFrame, textvariable=self.plotYTo, width=5).grid(row=1, column=3)
        tk.Label(rangeFrame, text="[Y for (m)post2d only]").grid(row=2, columnspan=4)
        tk.Button(midFrame1, text="Go", command=self.Go).pack(
            side=tk.RIGHT, anchor=tk.NE, padx=4
        )
        tk.Button(midFrame1, text="Save model", command=self.SaveModel).pack(
            side=tk.RIGHT, anchor=tk.NE, padx=4
        )
        tk.Button(midFrame1, text="Load model", command=self.LoadModel).pack(
            side=tk.RIGHT, anchor=tk.NE, padx=4
        )
        midFrame2 = tk.Frame(parent)
        midFrame2.pack(side=tk.TOP, fill=tk.X, pady=4)
        tk.Checkbutton(
            midFrame2,
            text="Don't fit (report goodness-of-fit only)",
            variable=self.nofit,
        ).pack(side=tk.LEFT, anchor=tk.W, padx=8)
        tk.Entry(midFrame2, textvariable=self.margErrVar, width=5).pack(
            side=tk.LEFT, anchor=tk.W
        )
        tk.Checkbutton(
            midFrame2, text="Error bar by marginalising", variable=self.margErr
        ).pack(side=tk.LEFT, anchor=tk.W)
        midFrame3 = tk.Frame(parent)
        midFrame3.pack(side=tk.TOP, fill=tk.X)
        tk.Label(midFrame3, text="Results:").pack(side=tk.LEFT, anchor=tk.SW)
        if dismissCommand is None:
            dismissCommand = parent.quit
        tk.Button(midFrame3, text="Dismiss", command=dismissCommand).pack(
            side=tk.RIGHT, padx=4, pady=4
        )
        tk.Button(midFrame3, text="Clear results", command=self.ClearResults).pack(
            side=tk.RIGHT, padx=4, pady=4
        )
        self.Results = ScrolledText(
            parent, height=31, width=90, font=("Courier", 10), state=tk.DISABLED
        )
        self.Results.tag_config("result", foreground="#1e90ff")  # dodger blue
        self.Results.tag_config("commentary", foreground="#ff8c00")  # dark orange
        self.Results.tag_config("error", foreground="#8b0000")  # dark red
        self.Results.pack(side=tk.TOP, expand=1, fill=tk.BOTH)

    def LoadModel(self):
        """Get filename and read model from file."""
        fileName = tk_filedialog.askopenfilename(
            parent=self.parent,
            initialdir=self.initialdir,
            filetypes=[("mfit model files", "*.model"), ("All files", "*")],
        )
        if fileName != "":
            self.ReadModel(fileName)

    def ReadModel(self, fileName):
        """Read model from file."""
        try:
            fil = open(fileName, "r")
            text = fil.read()
            fil.close()
        except IOError as e:
            (errNo, errStr) = e.args
            self.ShowResult("Error reading %s: %s\n" % (fileName, errStr), "error")
        else:
            self.SetModel(text)

    def SetModel(self, text):
        """Set model text."""
        self.ModelText.delete(1.0, tk.END)
        self.ModelText.insert(tk.END, text)

    def ClearResults(self):
        """Clear results window."""
        self.Results.configure(state=tk.NORMAL)
        self.Results.delete(1.0, tk.END)
        self.Results.configure(state=tk.DISABLED)

    def SaveModel(self):
        """Get filename and write model to file."""
        fileName = tk_filedialog.asksaveasfilename(
            parent=self.parent,
            initialdir=self.initialdir,
            filetypes=[("mfit model files", "*.model"), ("All files", "*")],
        )
        if fileName != "":
            self.WriteModel(fileName)

    def WriteModel(self, fileName):
        """Write model text to file."""
        fil = open(fileName, "w")
        fil.write(self.ModelText.get(1.0, tk.END))
        fil.close()

    def _ChangeFileName(self):
        newName = tk.filedialog.askopenfilename(
            parent=self.parent,
            initialdir=self.initialdir,
            title="Choose data file for fit",
            filetypes=[
                ("(OI-)FITS files", "*fits"),
                ("COAST Mapping Data files", "*.mapdat"),
                ("wbCalib / nbCalib files", "*calib"),
                ("All files", "*"),
            ],
        )
        if newName != "":
            self.fileName.set(newName)

    def ShowResult(self, text, tag):
        """Display text in 'Results'."""
        self.Results.configure(state=tk.NORMAL)
        self.Results.insert(tk.END, text, tag)
        self.Results.yview(tk.END)
        self.Results.configure(state=tk.DISABLED)
        self.parent.update_idletasks()

    def Go(self):
        """Fit the current model."""
        # Execute pre-callback
        if callable(self.preFitCallback):
            if not self.preFitCallback():
                return
        # Write model text to tempfile
        self._tempName = tempfile.mktemp(".model")
        self.WriteModel(self._tempName)
        # Run clfit so we can grab its output
        args = ["nice", self.exe, "--device", self.device]
        try:
            c = float(self.calErr.get())
        except ValueError:
            pass
        else:
            args += f"--calerr {c:.3f}".split()
        try:
            cwl = float(self.cwl.get())
            bw = float(self.bw.get())
        except ValueError:
            try:
                wlmin = float(self.wlmin.get())
                wlmax = float(self.wlmax.get())
                args += f"--waverange {wlmin:.2f} {wlmax:.2f}".split()
            except ValueError:
                pass  # don't specify waveband(s)
        else:
            args += f"--waveband {cwl:.2f} {bw:.2f}".split()
        try:
            target_id = int(self.target_id.get())
            args += f"--target_id {target_id}".split()
        except ValueError:
            pass
        p = self.selPlot.get()
        if p != self.plots[0]:  # not 'No plot'
            if p == "post" or p == "mpost":
                try:
                    index = int(self.plotXIndex.get())
                except ValueError:
                    index = 1
            if p == "post2d" or p == "mpost2d":
                try:
                    indx = (int(self.plotXIndex.get()), int(self.plotYIndex.get()))
                except ValueError:
                    indx = (1, 2)
            try:
                xmin = float(self.plotXFrom.get())
                xmax = float(self.plotXTo.get())
                if p[-2:] == "2d":
                    ymin = float(self.plotYFrom.get())
                    ymax = float(self.plotYTo.get())
            except ValueError:
                if p == "post" or p == "mpost":
                    args += f"--plot {p} {index}".split()
                elif p == "post2d" or p == "mpost2d":
                    args += f"--plot {p} {indx[0]} {indx[1]}".split()
                else:
                    args += f"--plot {p}".split()
            else:
                if p == "post" or p == "mpost":
                    args += f"--zoomplot {p} {index} {xmin} {xmax}".split()
                elif p == "post2d" or p == "mpost2d":
                    args += (
                        f"--zoomplot {p} {indx[0]} {indx[1]} {xmin:.4f} {xmax:.4f}"
                        f" {ymin:.4f} {ymax:.4f}".split()
                    )
                else:
                    args += f"--zoomplot {p} {xmin:.4f} {xmax:.4f}".split()
        if self.nofit.get():
            args += ["--nofit"]
        if self.margErr.get():
            args += f"--margerr {self.margErrVar.get()}".split()
        args += [self.fileName.get(), self._tempName]
        self.ShowResult("Running %s:\n" % " ".join(args), tag="commentary")

        # https://gitpress.io/u/1282/tkinter-read-async-subprocess-output
        self._proc = Popen(args, bufsize=10, stdout=PIPE, stderr=STDOUT, close_fds=True)
        oldflags = fcntl.fcntl(self._proc.stdout, fcntl.F_GETFL)
        fcntl.fcntl(self._proc.stdout, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
        self.parent.createfilehandler(
            self._proc.stdout, tk.READABLE, self._HandleChildOutput
        )

    def _HandleChildOutput(self, fd, mask):
        """Handle output from child process."""
        self._ShowOutput()
        returncode = self._proc.poll()
        if returncode is not None:
            # child process completed
            time.sleep(0.5)  # wait for last output
            self._ShowOutput()
            if returncode != 0:
                self.ShowResult(f"Subprocess exited with code {returncode}\n", "error")
            else:
                self.ShowResult("Subprocess exited normally\n", "commentary")
            self.parent.deletefilehandler(self._proc.stdout)
            os.remove(self._tempName)
            # Execute post-callback
            if callable(self.postFitCallback):
                self.postFitCallback()

    def _ShowOutput(self):
        """Read child process output and pass to ShowResult()."""
        try:
            result = self._proc.stdout.read()
        except IOError as e:
            (errNo, errMsg) = e.args
            self.ShowResult("I/O Error %d: %s\n" % (errNo, errMsg), "commentary")
        else:
            self.ShowResult(result, "result")
コード例 #20
0
class clientUI():
    def __init__(self):
        self.first_click = True;

    def start(self):
        print("Starting clientUI...")
        self.initDisplay()

        self.ui_messages.insert(tkinter.END, "Adding a message to the text field...\n")
        self.ui_input.insert(tkinter.END, "<Enter message>")

        # This call to mainloop() is blocking and will last for the lifetime
        # of the GUI.
        self.ui_top.mainloop()

        # Should only get here after destroy() is called on ui_top
        print("Stopping clientUI...")

    def initDisplay(self):
        self.ui_top = tkinter.Tk()
        self.ui_top.wm_title("GUI Demo")
        self.ui_top.resizable('1','1')
        self.ui_top.protocol("WM_DELETE_WINDOW", self.eventDeleteDisplay)
        
        self.ui_messages = ScrolledText(
            master=self.ui_top,
            wrap=tkinter.WORD,
            width=50,  # In chars
            height=25)  # In chars     

        self.ui_input = tkinter.Text(
            master=self.ui_top,
            wrap=tkinter.WORD,
            width=50,
            height=4)
        
        # Bind the button-1 click of the Entry to the handler
        self.ui_input.bind('<Button-1>', self.eventInputClick)
        
        self.ui_button_send = tkinter.Button(
            master=self.ui_top,
            text="Send",
            command=self.sendMsg)

        self.ui_button_file = tkinter.Button(
            master=self.ui_top,
            text="File",
            command=self.sendFile)

        # Compute display position for all objects
        self.ui_messages.pack(side=tkinter.TOP, fill=tkinter.BOTH)
        self.ui_input.pack(side=tkinter.TOP, fill=tkinter.BOTH)
        self.ui_button_send.pack(side=tkinter.LEFT)
        self.ui_button_file.pack(side=tkinter.RIGHT)


    # SEND button pressed
    def sendMsg(self):
        # Get user input (minus newline character at end)
        msg = self.ui_input.get("0.0", tkinter.END+"-1c")

        print("UI: Got text: '%s'" % msg)

        # Add this data to the message window
        self.ui_messages.insert(tkinter.INSERT, "%s\n" % (msg))
        self.ui_messages.yview(tkinter.END)  # Auto-scrolling
        
        # Clean out input field for new data
        self.ui_input.delete("0.0", tkinter.END)


    # FILE button pressed
    def sendFile(self):
        file = askopenfilename()

        if(len(file) > 0 and os.path.isfile(file)):
            print("UI: Selected file: %s" % file)
        else:
            print("UI: File operation canceled")

    # Event handler - User closed program via window manager or CTRL-C
    def eventDeleteDisplay(self):
        print("UI: Closing")

        # Continuing closing window now
        self.ui_top.destroy()

    # Event handler - User clicked inside the "ui_input" field
    def eventInputClick(self, event):
        if(self.first_click):
            # If this is the first time the user clicked,
            # clear out the tutorial message currently in the box.
            # Otherwise, ignore it.
            self.ui_input.delete("0.0", tkinter.END)
            self.first_click = False;
コード例 #21
0
class PfBGUI:
    """
    the GUI for selecting pixel centers from image as a set of points
    """

    hypdatadir = ""  # location of hyperspectral data, initial suggestion in file dialog

    def __init__(self, master, openfilelist=None, exportpointlist=None):
        """ 
        signalPfB: variable to signal the caller that we are finished, type DoubleVar() 
        openfilelist: list of the loaded hyperspectral file name and handles: [ filename filehandle datahandle ]
            intially, when loading the hyperspectral handles are set to None; they are assigned when file is opened for e.g. plotting
        exportpointlist: output list of tuples (id,x,y), where x,y are point (pixel centre) coordinates in the global projected system
            the pointlist created here is appended to exportpointlist
        if called with an exportpointlist, upon exit emits the signal master.<<PfBGUI_exit>>
        """

        self.master = master  # the master is likely tkroot
        self.openfilelist = openfilelist
        self.exportpointlist = exportpointlist

        # Show the GUI in a Toplevel window instead of Root.
        # This allows many such programs to be run independently in parallel.
        self.w = Toplevel(master)
        self.w.title("GUI for selecting pixels based on band values")

        self.bandnames = []  # list of band names as strings
        self.coordlist = [
            [], []
        ]  # list of coordinate points as produced by np.nonzero(), i.e., list of two lists, containing x and y coordinates, respectively
        # NOTE: these are image coordinates (line,pixel), i.e., (y,x)
        #  will be upended to exportpointlist on exit
        self.DIV = StringVar()  # Data Ignore Value
        self.DIV.set("")
        self.fig_hypdata = None  # figure handle for the image of th selected band
        self.xlim = [
        ]  # plotting limits for fig_hypdata: these will be retained during band and mask changes
        self.ylim = []
        self.figmask = None  # handle for the mask plt.imshow object

        self.band = StringVar(
        )  # tkinter string to set and get the value in band optionmenu

        self.textlog = ScrolledText(self.w, height=6)

        #just in case, put everythin in a frame, stuff can be added later if needed
        self.frame_buttons = Frame(self.w)

        bw = 35  # button width
        self.button_quit = Button(self.frame_buttons,
                                  text='´Done',
                                  width=bw,
                                  command=self.buttondone)
        self.button_datafile = Button(self.frame_buttons,
                                      text='Load datafile',
                                      width=bw,
                                      command=self.datafile)
        self.button_savepoints = Button(self.frame_buttons,
                                        text="save points in file",
                                        width=bw,
                                        command=self.savepoints)

        self.combo_band = ttk.Combobox(self.frame_buttons,
                                       textvariable=self.band,
                                       values=["select band"])
        self.combo_band.bind("<<ComboboxSelected>>", self.selectband)
        self.combo_band['width'] = bw - 5
        self.combo_band['state'] = DISABLED

        self.button_plotband = Button(self.frame_buttons,
                                      text='Plot band',
                                      width=bw,
                                      command=self.plotband,
                                      state=DISABLED)
        self.label_min = Label(self.frame_buttons,
                               width=bw,
                               text="Lower value:")
        self.minvaluestring = StringVar()
        self.minvaluestring.set("-")
        self.entry_minvalue = Entry(self.frame_buttons,
                                    textvariable=self.minvaluestring)
        self.label_max = Label(self.frame_buttons,
                               width=bw,
                               text="Upper value:")
        self.maxvaluestring = StringVar()
        self.maxvaluestring.set("-")
        self.entry_maxvalue = Entry(self.frame_buttons,
                                    textvariable=self.maxvaluestring)
        self.button_applyrange = Button(self.frame_buttons,
                                        text='Pick points',
                                        width=bw,
                                        command=self.applyrange,
                                        state=DISABLED)

        self.label_DIV = Label(self.frame_buttons,
                               width=bw,
                               text="Data Ignore Value:")
        self.entry_DIV = Entry(self.frame_buttons,
                               width=bw,
                               textvariable=self.DIV)

        self.label_id = Label(self.frame_buttons,
                              width=bw,
                              text="ID string for points:")
        self.point_id = StringVar()
        self.point_id.set("THRSHLD")
        self.entry_id = Entry(self.frame_buttons,
                              width=bw,
                              textvariable=self.point_id)

        self.label_N = Label(self.frame_buttons, width=bw, text="Points: 0")

        self.textlog.pack(side='bottom')

        if self.openfilelist is None:
            self.button_datafile.pack(side='top')
        else:
            # load the data file directly
            # assume that at least file name is given
            if self.openfilelist[1] is None or self.openfilelist[2] is None:
                # the data files are not opened yet
                self.load_hypdata()
            self.fill_bandnames()

        self.combo_band.pack(side='top')
        self.button_plotband.pack(side='top')
        self.label_min.pack(side='top')
        self.entry_minvalue.pack(side='top')
        self.label_max.pack(side='top')
        self.entry_maxvalue.pack(side='top')
        self.button_applyrange.pack(side='top')
        self.button_savepoints.pack(side='top')
        self.label_N.pack(side='top')
        self.label_DIV.pack(side='top')
        self.entry_DIV.pack(side='top')
        self.label_id.pack(side='top')
        self.entry_id.pack(side='top')

        self.button_quit.pack(side='bottom')

        self.frame_buttons.pack(side='left')

    def datafile(self):
        """
        get data file name and load metadata
        """

        filename1 = filedialog.askopenfilename(
            initialdir=self.hypdatadir,
            title="Choose hyperspectal data file",
            filetypes=(("ENVI header files", "*.hdr"), ("all files", "*.*")))

        if filename1 != "":
            self.openfilelist = [filename1, None, None]
            self.load_hypdata()
            self.fill_bandnames()

        shortfilename = os.path.split(filename1)[1]
        shortfilename = os.path.splitext(shortfilename)[0]
        self.button_datafile.configure(text="File: " + shortfilename)

    def load_hypdata(self):
        """
        load the file handles into openfilelist and check for wavelength data
        """
        # open the data file -- reads only metadata
        hypdata = spectral.open_image(self.openfilelist[0])
        # hypdata.metadata is of type dict, use e.g. hypdata.metadata.keys()
        # print(hypdata.metadata.keys())

        if hypdata.interleave == 1:
            self.printlog(self.openfilelist[0] + " Band interleaved (BIL) \n")
        else:
            self.printlog(
                self.openfilelist[0] +
                " not BIL -- opening still as BIL -- will be slower \n")
        hypdata_map = hypdata.open_memmap()
        self.printlog(
            "data file dimensions " +
            ", ".join([str(i) for i in hypdata_map.shape]) +
            "\n")  #shape[0]==lines, shape[1]==pixels, shape[2]==bands

        # save the handles to the openfilelist
        self.openfilelist = [self.openfilelist[0], hypdata, hypdata_map]

    def fill_bandnames(self):
        """
        Retrieve band names from the datafile metadata and fill the OptionMenu 
        Sets self.DIV Entry (Data Ignore Value)
        """
        hypfilename = self.openfilelist[0]
        hypdata = self.openfilelist[1]

        self.bandnames = []
        self.wl_hyp, wl_found = get_wavelength(hypfilename, hypdata)

        if 'band names' in hypdata.metadata:
            self.bandnames = hypdata.metadata['band names']
            # add wavelength as integer for each band name
            self.bandnames = [
                str(int(i)) + " " + j
                for i, j in zip(self.wl_hyp, self.bandnames)
            ]
        else:
            # name as wavelength: even if not given, negative integers are in wl_hyp
            self.bandnames = [str(int(i)) for i in self.wl_hyp]

        DIV = get_DIV(hypfilename, hypdata)
        if DIV is not None:
            self.DIV.set(str(DIV))
            self.entry_DIV.delete(0, END)
            self.entry_DIV.insert(0, str(DIV))
        # fill the band name ComboBox
        self.combo_band['state'] = ACTIVE
        self.combo_band.configure(values=self.bandnames)
        self.combo_band.delete(0, END)
        self.combo_band.insert(0, self.bandnames[0])
        self.selectband()

        self.button_plotband.configure(state=ACTIVE)
        self.button_applyrange.configure(state=ACTIVE)

    def selectband(self, event=None):
        """
        Activate a selection in the band selection ComboBox 
        and load pixel value ranges
        """
        choice = self.combo_band.get()
        bandnumber = self.bandnames.index(choice)
        bandimage = self.openfilelist[2][:, :, bandnumber]
        if self.DIV.get() != "":
            DIV = float(self.DIV.get())
        else:
            DIV = None
        i_data = np.nonzero(bandimage != DIV)
        minvalue = np.min(bandimage[i_data])
        maxvalue = np.max(bandimage[i_data])
        self.entry_minvalue.delete(0, END)
        # to avoid digitization errors, we must always know if the field contains the actual min and max
        self.entry_minvalue.insert(
            0, "min=" + str(minvalue)
        )  #prefix with min to indicate that we have the histogram minimum
        self.entry_maxvalue.delete(0, END)
        self.entry_maxvalue.insert(0, "max=" + str(maxvalue))

    def plotband(self):
        """ 
        plot the band using imshow
        """
        bandnumber = self.bandnames.index(self.band.get())
        self.printlog("Plotting band " + self.band.get() + " [" +
                      str(bandnumber) + "]\n")

        hypfilename = self.openfilelist[0]
        hypdata = self.openfilelist[1]
        hypdata_map = self.openfilelist[2]

        self.xlim = None
        self.ylim = None
        if self.fig_hypdata is not None:
            if self.fig_hypdata.number in plt.get_fignums():
                # save the current view if the window exists
                self.xlim = self.fig_hypdata.axes[0].get_xlim()
                self.ylim = self.fig_hypdata.axes[0].get_ylim()

        if self.figmask is not None:
            # remove the old mask
            self.figmask.remove()
            self.figmask = None

        self.fig_hypdata = plot_singleband(hypfilename,
                                           hypdata,
                                           hypdata_map,
                                           bandnumber,
                                           fig_hypdata=self.fig_hypdata,
                                           outputcommand=self.printlog)

        if self.xlim is not None:
            # restore the previous view
            self.fig_hypdata.axes[0].set_xlim(self.xlim)
            self.fig_hypdata.axes[0].set_ylim(self.ylim)
            self.fig_hypdata.canvas.draw()

    def savepoints(self):
        """
        save the created points (i.e., their coordinates, not spectra) to a text file.
        """
        if len(self.coordlist[0]) > 0:
            filename = filedialog.asksaveasfilename(
                initialdir=self.hypdatadir,
                title="Save point coordinates (X,Y)",
                filetypes=(("txt files", "*.txt"), ("csv files", "*.csv"),
                           ("all files", "*.*")))
            if filename != '':
                with open(filename, 'w') as file:
                    file.write("id,x,y\n")
                    pointlist = self.get_pointlist()
                    for point in pointlist:
                        pointstring = point[0] + "," + str(
                            point[1]) + ',' + str(point[2]) + '\n'
                        file.write(pointstring)
                self.printlog("Point coordinates saved to " + filename + ".\n")
            else:
                self.printlog("Saving of point coordinates aborted.\n")
        else:
            self.printlog("savepoints(): No points, nothing saved.\n")

    def applyrange(self):
        """
        Create the points
        """

        hypfilename = self.openfilelist[0]
        hypdata_map = self.openfilelist[2]
        bandnumber = self.bandnames.index(self.band.get())
        bandimage = hypdata_map[:, :, bandnumber]
        if self.DIV.get() != "":
            DIV = float(self.DIV.get())
        else:
            DIV = None
        i_data = np.nonzero(bandimage != DIV)

        if self.minvaluestring.get()[0] == "m":
            # the entry field contains unmodified histogram minimum
            minvalue = np.min(bandimage[i_data])
        else:
            minvalue = float(self.minvaluestring.get())

        if self.maxvaluestring.get()[0] == "m":
            # the entry field contains unmodified histogram maximum
            maxvalue = np.max(bandimage[i_data])
        else:
            maxvalue = float(self.maxvaluestring.get())

        self.coordlist = np.nonzero(
            np.logical_and(
                np.logical_and(bandimage >= minvalue, bandimage <= maxvalue),
                bandimage != DIV))
        N = len(self.coordlist[0])
        self.label_N.configure(text="Points: " + str(N))

        # plot the mask only if the band image exists
        if self.fig_hypdata is not None:
            if self.fig_hypdata.number in plt.get_fignums():
                # just in case: save the current view
                self.xlim = self.fig_hypdata.axes[0].get_xlim()
                self.ylim = self.fig_hypdata.axes[0].get_ylim()
                mask = np.zeros_like(
                    bandimage, dtype=float)  # NaN's don't work with integers
                mask[self.coordlist] = np.NaN  # NaN plots as transparent

                if self.figmask is not None:
                    # remove the old mask
                    self.figmask.remove()
                self.figmask = self.fig_hypdata.axes[0].imshow(
                    mask, interpolation='nearest')

                # restore the previous view
                self.fig_hypdata.axes[0].set_xlim(self.xlim)
                self.fig_hypdata.axes[0].set_ylim(self.ylim)

                self.fig_hypdata.canvas.draw()

    def buttondone(self):
        """
        function to end the misery and return the points
        """
        if self.fig_hypdata is not None:
            plt.close(self.fig_hypdata)
        if self.exportpointlist is not None and len(self.coordlist[0]) > 0:
            pointlist = self.get_pointlist()
            self.exportpointlist += pointlist
            self.master.event_generate("<<PfBGUI_exit>>", when="tail")
            self.w.destroy(
            )  # if we were called to create points, don't destroy root, computation will continue elsewhere
        else:
            self.master.destroy(
            )  # destruction of root will exit the main loop and allow the program to exit

    def get_pointlist(self):
        """
        outputs pointlist, a list of tuples (id,x,y) using ID and self.coordlist (y_loc, x_loc)
        x,y are in global coordinates
        """
        id = self.point_id.get()
        IDlist = [id] * len(self.coordlist[0])
        pointmatrix_local = np.matrix(
            self.coordlist).transpose()[:, (1, 0)]  # swap x & y
        pointmatrix_global = image2world(self.openfilelist[0],
                                         pointmatrix_local)
        pointlist = [(id, Q[0], Q[1])
                     for id, Q in zip(IDlist, pointmatrix_global.tolist())]
        return pointlist

    def printlog(self, text):
        """
        Output to log window. Note: no newline added beteen inputs.
        text need not be a string, will be converted when printing.
        """
        self.textlog.insert(END, str(text))
        self.textlog.yview(END)
        self.master.update_idletasks()
コード例 #22
0
ファイル: uiyt.py プロジェクト: katyon08/YouSubwayEscalator
class App(Frame):
    lock = False

    def __init__(self, master=None):
        Frame.__init__(self, master)
        # self. grid()
        self.pack()
        self.master = master
        self.download_type = IntVar()
        self.audio_only = BooleanVar()
        self.from_url = StringVar()
        self.to_url = StringVar()

        self.radois = Frame(self, relief=RAISED, borderwidth=1)
        self.radois.pack(fill=BOTH, expand=True)

        self.download_playlist = Radiobutton(self.radois,
                                             text='Плейлист целиком',
                                             variable=self.download_type,
                                             value=0)
        self.download_playlist.pack(ipadx=10, ipady=10, side=LEFT)

        self.download_file_only = Radiobutton(self.radois,
                                              text='Только файл',
                                              variable=self.download_type,
                                              value=1)
        self.download_file_only.pack(ipadx=10, ipady=10, side=LEFT)

        self.download_url_label = Label(text="Откуда качать")
        self.download_url_label.pack(ipadx=10, ipady=10)

        self.download_url = Entry(self.master, textvariable=self.from_url)
        self.download_url.pack(ipadx=10, ipady=3, expand=True, fill=BOTH)

        self.download_url_label = Label(text="Куда качать")
        self.download_url_label.pack(ipadx=10, ipady=10)

        self.save_url = Entry(self.master, textvariable=self.to_url)
        self.save_url.pack(ipadx=10, ipady=3, expand=True, fill=BOTH)

        self.audio_checkbox = Checkbutton(self.master,
                                          text='Только аудио',
                                          variable=self.audio_only,
                                          onvalue=True,
                                          offvalue=False)
        self.audio_checkbox.pack(ipadx=10, ipady=10)

        self.message_button = Button(text="Скачать", command=self.run_program)
        self.message_button.pack(ipadx=10, ipady=10)

        self.editArea = ScrolledText(master=self.master,
                                     wrap=WORD,
                                     width=20,
                                     height=10)
        self.editArea.pack(padx=10, pady=10, fill=BOTH, expand=True)

    def run_program(self):

        if not self.lock:
            self.lock = True
            thread = threading.Thread(
                target=self.run,
                args=(),
            )
            thread.daemon = True
            thread.start()
        else:
            messagebox.showerror(
                "Error",
                "В данный момент уже идет загрузка, подождите окончания предыдущей и попробуйте снова!"
            )

    def run(self):
        if self.download_type.get() == 0:
            self.edit_print("Качаем весь плейлист")
            download_playlist(self.from_url.get(), self.to_url.get(),
                              self.audio_only.get())
        elif self.download_type == 1:
            self.edit_print("Качаем один файл")
            download_song(self.from_url.get(), self.to_url.get(),
                          self.audio_only.get())
        self.lock = False

    def edit_print(self, text):
        self.editArea.insert(END, text + "\n")
        self.editArea.yview(END)
コード例 #23
0
class clientUI():
    def __init__(self, a_socket, a_username):
        self.first_click = True;
        self.a_socket = a_socket
        self.a_username = a_username

    def start(self):
        print("Starting clientUI...")
        self.initDisplay()

        self.ui_messages.insert(tkinter.END, "Adding a message to the text field...\n")
        self.ui_input.insert(tkinter.END, "<Enter message>")

    def execute(self):
        self.ui_top.mainloop() # This call to mainloop() is blocking and will last for the lifetime of the GUI.
        print("Stopping clientUI...") # Should only get here after destroy() is called on ui_top

    def initDisplay(self):
        self.ui_top = tkinter.Tk()
        self.ui_top.wm_title("GUI Demo")
        self.ui_top.resizable('1','1')
        self.ui_top.protocol("WM_DELETE_WINDOW", self.eventDeleteDisplay)
        
        self.ui_messages = ScrolledText(
            master=self.ui_top,
            wrap=tkinter.WORD,
            width=50,  # In chars
            height=25)  # In chars     

        self.ui_input = tkinter.Text(
            master=self.ui_top,
            wrap=tkinter.WORD,
            width=50,
            height=4)
        
        # Bind the button-1 click of the Entry to the handler
        self.ui_input.bind('<Button-1>', self.eventInputClick)
        
        self.ui_button_send = tkinter.Button(
            master=self.ui_top,
            text="Send",
            command=self.sendMsg)

        self.ui_button_file = tkinter.Button(
            master=self.ui_top,
            text="File",
            command=self.sendFile)

        # Compute display position for all objects
        self.ui_messages.pack(side=tkinter.TOP, fill=tkinter.BOTH)
        self.ui_input.pack(side=tkinter.TOP, fill=tkinter.BOTH)
        self.ui_button_send.pack(side=tkinter.LEFT)
        self.ui_button_file.pack(side=tkinter.RIGHT)


    # SEND button pressed
    def sendMsg(self):
        # Get user input (minus newline character at end)
        msg = self.a_username + ": " + self.ui_input.get("0.0", tkinter.END+"-1c")
        msg_len = len(msg)

        print("UI: Got text: '%s'" % msg)
        
        print("Starting send thread . . .")           
        thread1 = sndThread(self.a_socket, self.a_username, msg_len, msg) #Launch sending Thread ###############################################################
        thread1.daemon = True
        thread1.start()

        
        self.ui_messages.insert(tkinter.INSERT, "%s\n" % (msg)) # Add this data to the message window
        self.ui_messages.yview(tkinter.END)  # Auto-scrolling
        
        # Clean out input field for new data
        self.ui_input.delete("0.0", tkinter.END)


    # FILE button pressed
    def sendFile(self):
        file = askopenfilename()

        if(len(file) > 0 and os.path.isfile(file)):
            print("UI: Selected file: %s" % file)
        else:
            print("UI: File operation canceled")

    # Event handler - User closed program via window manager or CTRL-C
    def eventDeleteDisplay(self):  
        leave_msg = "CHAT/1.0 LEAVE\r\nUsername: "******"\r\n\r\n"
        try: #SEND
            leave_raw_bytes = bytes(leave_msg,'ascii')
            leave_bytes_sent = self.a_socket.sendall(leave_raw_bytes)
        except socket.error as msg:
            print("Error: send() failed\nDescription: " + str(msg))
            sys.exit()
     
        try: #CLOSE SOCKET
            self.a_socket.close()
        except socket.error as msg:
            print("Error: unable to close() socket\nDescription: " + str(msg))
            sys.exit()
        print("Socket closed, now exiting")
        
        print("UI: Closing")
        self.ui_top.destroy() # Continuing closing window now

    # Event handler - User clicked inside the "ui_input" field
    def eventInputClick(self, event):
        if(self.first_click): # If this is the first time the user clicked, clear out the tutorial message currently in the box. Otherwise, ignore it.
            self.ui_input.delete("0.0", tkinter.END)
            self.first_click = False;
コード例 #24
0
class clientUI():
    def __init__(self):
        self.first_click = True

    def start(self):
        print("Запускаем чат...")
        self.initDisplay()
        self.ui_messages.insert(tkinter.END,
                                "Добавление сообщения в текстовое поле...\n")
        self.ui_input.insert(tkinter.END, "<Отправить сообщение>")
        self.ui_top.mainloop()
        print("Останавливаем чат...")

    def initDisplay(self):
        self.ui_top = tkinter.Tk()
        self.ui_top.wm_title("Это чат")
        self.ui_top.resizable('1', '1')
        self.ui_top.protocol("WM_DELETE_WINDOW", self.eventDeleteDisplay)

        self.ui_messages = ScrolledText(master=self.ui_top,
                                        wrap=tkinter.WORD,
                                        width=50,
                                        height=25)

        self.ui_input = tkinter.Text(master=self.ui_top,
                                     wrap=tkinter.WORD,
                                     width=50,
                                     height=4)

        # Привязать <Кнопка-1> клика Entry к обработчику
        self.ui_input.bind('<Кнопка-1>', self.eventInputClick)
        self.ui_button_send = tkinter.Button(master=self.ui_top,
                                             text="Отправить",
                                             command=self.sendMsg)

        self.ui_button_file = tkinter.Button(master=self.ui_top,
                                             text="Файл",
                                             command=self.sendFile)

        # Вычисляем положение дисплея для всех объектов
        self.ui_messages.pack(side=tkinter.TOP, fill=tkinter.BOTH)
        self.ui_input.pack(side=tkinter.TOP, fill=tkinter.BOTH)
        self.ui_button_send.pack(side=tkinter.LEFT)
        self.ui_button_file.pack(side=tkinter.RIGHT)

    # Кнопка ОТПРАВИТЬ
    def sendMsg(self):
        msg = self.ui_input.get("0.0", tkinter.END + "-1c")
        print("Чат: Получил сообщение: '%s'" % msg)
        self.ui_messages.insert(tkinter.INSERT, "%s\n" % (msg))
        self.ui_messages.yview(tkinter.END)
        self.ui_input.delete("0.0", tkinter.END)

    # Кнопка ФАЙЛ
    def sendFile(self):
        file = askopenfilename()
        if (len(file) > 0 and os.path.isfile(file)):
            print("Чат: Выбран файл: %s" % file)
        else:
            print("Чат: Отмена")

    # Закрытие Чата
    def eventDeleteDisplay(self):
        print("Чат: Закрытие")
        self.ui_top.destroy()

    # Обработчик события
    def eventInputClick(self, event):
        if (self.first_click):
            self.ui_input.delete("0.0", tkinter.END)
            self.first_click = False
コード例 #25
0
class disp_GUI:
    def __init__(self, master):

        self.master = master
        self.fig_hypdata = None
        self.hypdata = None  # This contains only the mos recently opened figure. Rather useless
        self.hypdata_map = None

        bw = 25  # buttonwidth

        # Show the GUI in a Toplevel window instead of Root.
        # This allows many such programs to be run independently in parallel.
        self.w = Toplevel(master)
        self.w.title("GUI for plotting data")

        self.redband_string = StringVar(
        )  # string to set and read option_redband OptionMenu
        self.greenband_string = StringVar(
        )  # string to set and read option_greenband OptionMenu
        self.blueband_string = StringVar(
        )  # string to set and read option_blueband OptionMenu
        self.monoband_string = StringVar(
        )  # string to set and read option_monoband OptionMenu
        self.redband_string.set("Red band")
        self.redband_string.set("Green band")
        self.redband_string.set("Blue band")
        self.redband_string.set("Monochrome band")

        self.textlog = ScrolledText(self.w, height=6)
        self.textlog.pack(side='bottom')

        self.frame_rgb = Frame(self.w)
        self.label_red = Label(self.frame_rgb, width=bw, text="Red channel")
        self.label_green = Label(self.frame_rgb,
                                 width=bw,
                                 text="Green channel")
        self.label_blue = Label(self.frame_rgb, width=bw, text="Blue channel")
        self.label_mono = Label(self.frame_rgb,
                                width=bw,
                                text="Monochrome channel")
        self.option_red = OptionMenu(self.frame_rgb, self.redband_string, '')
        self.option_red['width'] = bw - 5
        self.option_green = OptionMenu(self.frame_rgb, self.greenband_string,
                                       '')
        self.option_green['width'] = bw - 5
        self.option_blue = OptionMenu(self.frame_rgb, self.blueband_string, '')
        self.option_blue['width'] = bw - 5
        self.option_mono = OptionMenu(self.frame_rgb, self.monoband_string, '')
        self.option_mono['width'] = bw - 5
        self.label_red.pack(side='top')
        self.option_red.pack(side='top')
        self.option_red.configure(state=DISABLED)
        self.label_green.pack(side='top')
        self.option_green.pack(side='top')
        self.option_green.configure(state=DISABLED)
        self.label_blue.pack(side='top')
        self.option_blue.pack(side='top')
        self.option_blue.configure(state=DISABLED)
        self.label_mono.pack(side='top')
        self.option_mono.pack(side='top')
        self.option_mono.configure(state=DISABLED)
        self.frame_rgb.pack(side='right')

        self.frame_button = Frame(self.w)
        self.button_quit = Button(self.frame_button,
                                  width=bw,
                                  text='Quit',
                                  command=self.buttonquit)
        self.button_loaddata = Button(self.frame_button,
                                      width=bw,
                                      text='Load raster file',
                                      command=self.loaddatafile)
        self.button_plottrue = Button(self.frame_button,
                                      width=bw,
                                      text='Plot truecolor',
                                      command=self.plottrue,
                                      state=DISABLED)
        self.button_plotmono = Button(self.frame_button,
                                      width=bw,
                                      text='Plot monochrome',
                                      command=self.plotmono,
                                      state=DISABLED)
        self.button_plotnir = Button(self.frame_button,
                                     width=bw,
                                     text='Plot falsecolor NIR',
                                     command=self.plotnir,
                                     state=DISABLED)
        self.button_plotrgb = Button(self.frame_button,
                                     width=bw,
                                     text='Plot with three bands',
                                     command=self.plotrgb,
                                     state=DISABLED)
        self.button_loaddata.pack(side='top')
        self.button_plottrue.pack(side='top')
        self.button_plotnir.pack(side='top')
        self.button_plotrgb.pack(side='top')
        self.button_plotmono.pack(side='top')
        self.button_quit.pack(side='bottom')
        self.frame_button.pack(side='left')

        # load paths at the end of init (so messaging already exists)
        # self.foldername1 = 'D:\\mmattim\\wrk\\hyytiala-D\\' # where the data is. This is the initial value, will be modified later
        self.foldername1 = get_hyperspectral_datafolder(
            localprintcommand=self.printlog)

    def loaddatafile(self):
        """
        Open the hyperspectral file.
        """
        self.hypfilename = filedialog.askopenfilename(
            initialdir=self.foldername1,
            title="Choose a hyperspectral data file",
            filetypes=(("Envi hdr files", "*.hdr"), ("all files", "*.*")))

        if self.hypfilename != '':
            self.foldername1 = os.path.split(self.hypfilename)[0]
            self.hypdata_map = None
            self.hypdata = None
            self.button_plotmono.configure(state=DISABLED)
            self.button_plotrgb.configure(state=DISABLED)
            self.button_plotnir.configure(state=DISABLED)
            self.button_plottrue.configure(state=DISABLED)

            # try to have .hdr extension, although this should not be compulsory. No error checking here.
            if not self.hypfilename.endswith(".hdr"):
                self.hypfilename += '.hdr'

            # open the files and assign handles
            self.hypdata = spectral.open_image(self.hypfilename)
            self.hypdata_map = self.hypdata.open_memmap()

            # come up with band names
            wl_hyp, wl_found = get_wavelength(self.hypfilename, self.hypdata)
            #  best possible result "number:wavelength"
            bandnames = [
                '%3d :%6.1f nm' % (i + 1, wli) for i, wli in enumerate(wl_hyp)
            ]
            if wl_found:
                self.printlog(
                    "loaddatafile(): Found wavelength information in file " +
                    self.hypfilename + ".\n")
            else:
                self.printlog(
                    "loaddatafile(): No wavelength information in file " +
                    self.hypfilename + ".\n")
                # try to use band name information
                if 'band names' in self.hypdata.metadata:
                    bn = self.hypdata.metadata['band names']
                    bandnames = [
                        '%3d:%s' % (i + 1, wli) for i, wli in enumerate(bn)
                    ]

            # fill the option menus with wavelengths
            self.option_red['menu'].delete(0, END)
            self.option_green['menu'].delete(0, END)
            self.option_blue['menu'].delete(0, END)
            self.option_mono['menu'].delete(0, END)
            for choice_num in bandnames:
                choice = str(choice_num)
                self.option_red['menu'].add_command(
                    label=choice,
                    command=lambda v=choice: self.redband_string.set(v))
                self.option_green['menu'].add_command(
                    label=choice,
                    command=lambda v=choice: self.greenband_string.set(v))
                self.option_blue['menu'].add_command(
                    label=choice,
                    command=lambda v=choice: self.blueband_string.set(v))
                self.option_mono['menu'].add_command(
                    label=choice,
                    command=lambda v=choice: self.monoband_string.set(v))

            # make reasonable preselections for r,g,b
            if 'default bands' in self.hypdata.metadata:
                if len(self.hypdata.metadata['default bands']) > 2:
                    i_r = int(self.hypdata.metadata['default bands'][0]) - 1
                    i_g = int(self.hypdata.metadata['default bands'][1]) - 1
                    i_b = int(self.hypdata.metadata['default bands'][2]) - 1
                    # avoid official printing band names, they usually contain long crappy strings
                    self.printlog(
                        "loaddatafile(): Found default bands (%i,%i,%i) for plotting.\n"
                        % (i_r, i_g, i_b))
                else:
                    i_m = int(self.hypdata.metadata['default bands'][0]) - 1
                    i_r = i_m
                    i_g = i_m
                    i_b = i_m
                    # avoid official printing band names, they usually contain long crappy strings
                    self.printlog(
                        "loaddatafile(): Found one default band (%i) for plotting.\n"
                        % i_m)

            elif wl_found:
                i_r = abs(wl_hyp - 680).argmin()  # red band
                i_g = abs(wl_hyp - 550).argmin()  # green
                i_b = abs(wl_hyp - 450).argmin()  # blue
            else:
                # just use the first one or three bands
                if self.hypdata_map.shape[2] > 2:
                    # we have at least 3 bands
                    i_r = 0
                    i_g = 1
                    i_b = 2
                else:
                    # monochromatic, use first band only
                    i_r = 0
                    i_g = 0
                    i_b = 0
            # set monochrome to red
            i_m = i_r

            # set the optionmenus to their respective values
            self.redband_string.set(bandnames[i_r])
            self.greenband_string.set(bandnames[i_g])
            self.blueband_string.set(bandnames[i_b])
            self.monoband_string.set(bandnames[i_m])

            # wrap it up. Make sure all options are active and ready
            self.option_red.configure(state=ACTIVE)
            self.option_green.configure(state=ACTIVE)
            self.option_blue.configure(state=ACTIVE)
            self.option_mono.configure(state=ACTIVE)
            self.button_plotmono.configure(state=ACTIVE)
            self.button_plotrgb.configure(state=ACTIVE)
            if wl_found:
                self.button_plotnir.configure(state=ACTIVE)
                self.button_plottrue.configure(state=ACTIVE)

        else:
            self.printlog("loaddatafile(): No file name given.\n")

    def plotrgb(self):
        """
        plot in true color, ignore r,g,b band optionmenus
        """
        i_r = int(self.redband_string.get().split(':')[0]) - 1
        i_g = int(self.greenband_string.get().split(':')[0]) - 1
        i_b = int(self.blueband_string.get().split(':')[0]) - 1

        self.printlog("plotrgb(): bands %3d,%3d,%3d.\n" % (i_r, i_g, i_b))

        self.fig_hypdata = plot_hyperspectral(self.hypfilename,
                                              self.hypdata,
                                              self.hypdata_map,
                                              self.printlog,
                                              plotbands=[i_r, i_g, i_b])

    def plottrue(self):
        """
        plot using the r,g,b band optionmenus
        """
        wl_hyp, wl_found = get_wavelength(self.hypfilename, self.hypdata)
        if wl_found:
            i_r = abs(wl_hyp - 680).argmin()  # red band
            i_g = abs(wl_hyp - 550).argmin()  # green
            i_b = abs(wl_hyp - 450).argmin()  # blue
            self.printlog("plottrue(): %5.1f,%5.1f,%5.1f nm.\n" %
                          (wl_hyp[i_r], wl_hyp[i_g], wl_hyp[i_b]))
            self.fig_hypdata = plot_hyperspectral(self.hypfilename,
                                                  self.hypdata,
                                                  self.hypdata_map,
                                                  self.printlog,
                                                  plotbands=[i_r, i_g, i_b])
        else:
            # this should never happen, but just in case
            self.printlog(
                "plottrue(): No wavelength data available. This should never happen.\n"
            )

    def plotnir(self):
        """
        plot in falsecolor NIR, ignore r,g,b band optionmenus
        """
        wl_hyp, wl_found = get_wavelength(self.hypfilename, self.hypdata)
        if wl_found:
            i_r = abs(wl_hyp - 780).argmin()  # NIR band
            i_g = abs(wl_hyp - 680).argmin()  # red band
            i_b = abs(wl_hyp - 550).argmin()  # green
            self.printlog("plotnir(): %5.1f,%5.1f,%5.1f nm.\n" %
                          (wl_hyp[i_r], wl_hyp[i_g], wl_hyp[i_b]))
            self.fig_hypdata = plot_hyperspectral(self.hypfilename,
                                                  self.hypdata,
                                                  self.hypdata_map,
                                                  self.printlog,
                                                  plotbands=[i_r, i_g, i_b])
        else:
            # this should never happen, but just in case
            self.printlog(
                "plotnir(): No wavelength data available. This should never happen.\n"
            )

    def plotmono(self):
        """
        Plot the data with the band specified in the monochrome option menu
        """
        i_m = int(self.monoband_string.get().split(':')[0]) - 1
        plot_singleband(self.hypfilename,
                        self.hypdata,
                        self.hypdata_map,
                        i_m,
                        outputcommand=self.printlog)

    def printlog(self, text):
        """
        Output to log window. Note: no newline added beteen inputs.
        text need not be a string, will be converted when printing.
        """
        self.textlog.insert(END, str(text))
        self.textlog.yview(END)
        self.master.update_idletasks()

    def buttonquit(self):
        """
        function to end the misery
        note: the pyplot windows are not closed. Maybe, it would be nice to keep track of those to close them
        """
        set_hyperspectral_datafolder(self.foldername1)
        self.master.destroy(
        )  # destruction of root required for program to continue (to its end)
コード例 #26
0
class MainFrame(tk.Frame):
    def __init__(self, master=None, db_session=None):
        super().__init__(master)
        self.master = master
        self.db_session = db_session

        self.board_tile_width = 100

        x = self.master.winfo_screenwidth() // 2 - 150
        y = self.master.winfo_screenheight() // 2 - 50
        self.master.geometry("%dx%d+%d+%d" % (300, 275, x, y))
        self.master.resizable(False, False)

        padx = 10
        pady = 5

        self.tabs = Notebook(self)
        self.tabs.grid(row=0, column=0, sticky="NW")

        self.tabs_game = tk.Frame(self.tabs)
        self.tabs.add(self.tabs_game, text="Game")

        self.start_frame = tk.Frame(self.tabs_game)
        self.start_frame.grid(row=0, column=0, pady=pady, sticky="NW")
        self.start_btn = tk.Button(self.start_frame,
                                   text="Play",
                                   command=self.start_game)
        self.start_btn.grid(row=0, column=0, padx=padx, pady=pady, sticky="NW")
        self.ai_difficulty = tk.IntVar(self, -1)
        for ai_difficulty in [((0, 0), "2 players", -1),
                              ((1, 0), "Random AI", 0),
                              ((0, 1), "Normal AI", 1)]:
            radio_btn = tk.Radiobutton(
                self.start_frame,
                variable=self.ai_difficulty,
                text=ai_difficulty[1],
                val=ai_difficulty[2],
            )
            radio_btn.grid(row=ai_difficulty[0][1],
                           column=ai_difficulty[0][0] + 1,
                           pady=pady,
                           sticky="NW")

        self.status_frame = tk.Frame(self.tabs_game)
        self.status_frame.grid(row=1,
                               column=0,
                               padx=padx,
                               pady=pady,
                               sticky="NW")
        self.status_frame.grid_remove()

        self.status_label = tk.Label(self.status_frame, text="")
        self.status_label.grid(row=0, column=0, pady=pady, sticky="NW")

        self.draw_btn = tk.Button(self.status_frame,
                                  text="Claim draw",
                                  command=self.claim_draw)
        self.draw_btn.grid(row=0, column=1, padx=padx, pady=pady, sticky="NE")
        self.draw_btn.grid_remove()

        self.moves_text = ScrolledText(self.status_frame,
                                       width=20,
                                       height=3,
                                       state=tk.DISABLED)
        self.moves_text.grid(row=1, column=0, pady=pady)

        self.promotion_piece = tk.StringVar(self, "Q")
        self.promotion_piece_selection_frame = tk.Frame(self.tabs_game)
        self.promotion_piece_selection_frame.grid(row=3,
                                                  column=0,
                                                  padx=padx,
                                                  pady=pady)
        self.promotion_piece_selection_frame.grid_remove()
        promotion_label = tk.Label(self.promotion_piece_selection_frame,
                                   text="Promotion piece")
        promotion_label.grid(row=0, column=0, sticky="NW")
        for promotion_piece in [
            (0, "Knight", "N"),
            (1, "Bishop", "B"),
            (2, "Rook", "R"),
            (3, "Queen", "Q"),
        ]:
            radio_btn = tk.Radiobutton(
                self.promotion_piece_selection_frame,
                variable=self.promotion_piece,
                command=self.on_promotion_piece_selected,
                text=promotion_piece[1],
                val=promotion_piece[2],
            )
            radio_btn.grid(row=1, column=promotion_piece[0], pady=pady)

        self.view_control_btn_frame = tk.Frame(self.tabs_game)
        self.view_control_btn_frame.grid(row=3, column=0, padx=padx, pady=pady)
        self.view_control_btn_frame.grid_remove()

        self.previous_move_btn = tk.Button(self.view_control_btn_frame,
                                           text="Previous",
                                           command=self.previous_move)
        self.previous_move_btn.grid(row=0, column=0, padx=padx, pady=pady)

        self.next_move_btn = tk.Button(self.view_control_btn_frame,
                                       text="Next",
                                       command=self.next_move)
        self.next_move_btn.grid(row=0, column=1, padx=padx, pady=pady)

        self.save_game_btn = tk.Button(self.tabs_game,
                                       text="Save",
                                       command=self.db_save_game)
        self.save_game_btn.grid(row=4,
                                column=0,
                                padx=padx,
                                pady=pady,
                                sticky="NW")
        self.save_game_btn.grid_remove()

        self.tabs_database = tk.Frame(self.tabs)
        self.tabs.add(self.tabs_database, text="Database")

        self.pgn_label = tk.Label(self.tabs_database,
                                  text="Portable Game Notation")
        self.pgn_label.grid(row=0, column=0, padx=padx, sticky="NW")

        self.pgn_text = ScrolledText(self.tabs_database, width=20, height=3)
        self.pgn_text.grid(row=1, column=0, padx=padx, pady=pady, sticky="NW")

        pgn_btn_frame = tk.Frame(self.tabs_database)
        pgn_btn_frame.grid(row=2, column=0, pady=pady, sticky="NW")

        import_btn = tk.Button(pgn_btn_frame,
                               text="Import",
                               command=self.import_pgn)
        import_btn.grid(row=0, column=0, padx=padx, pady=pady)

        export_btn = tk.Button(pgn_btn_frame,
                               text="Export",
                               command=self.export_pgn)
        export_btn.grid(row=0, column=1, padx=padx, pady=pady)

        view_btn = tk.Button(pgn_btn_frame,
                             text="View",
                             command=lambda: self.start_game(view_mode=True))
        view_btn.grid(row=0, column=2, padx=padx, pady=pady)

        game_list_frame = tk.Frame(self.tabs_database)
        game_list_frame.grid(row=4, column=0, pady=pady)

        game_list_label = tk.Label(game_list_frame, text="Stored games")
        game_list_label.grid(row=0, column=0, padx=padx, sticky="NW")

        self.game_combobox = Combobox(game_list_frame, state="readonly")
        self.game_combobox.grid(row=1, column=0, padx=padx, pady=pady)

        load_btn = tk.Button(game_list_frame,
                             text="Load",
                             command=self.db_load_pgn)
        load_btn.grid(row=1, column=1, padx=padx, pady=pady)

        delete_btn = tk.Button(game_list_frame,
                               text="Delete",
                               command=self.db_delete_game)
        delete_btn.grid(row=1, column=2, padx=padx, pady=pady)

        self.db_load_games()

        self.tabs_settings = tk.Frame(self.tabs)
        self.tabs.add(self.tabs_settings, text="Settings")

        self.enable_sounds = tk.BooleanVar(
            value=self.db_get_setting("enable_sounds", "0") == "1")
        if system() != "Linux":
            sound_checkbtn = tk.Checkbutton(
                self.tabs_settings,
                text="Enable sounds",
                variable=self.enable_sounds,
                command=lambda: self.db_store_setting(
                    "enable_sounds", "1" if self.enable_sounds.get() else "0"),
            )
            sound_checkbtn.grid(row=0,
                                column=0,
                                padx=padx,
                                pady=pady,
                                sticky="NW")

        self.theme = tk.StringVar(self,
                                  self.db_get_setting("theme", "Classic"))

        theme_frame = tk.Frame(self.tabs_settings)
        theme_frame.grid(row=1, column=0, pady=pady)

        theme_label = tk.Label(theme_frame, text="Theme")
        theme_label.grid(row=0, column=0, padx=padx, sticky="NW")
        theme_combobox = Combobox(
            theme_frame,
            textvariable=self.theme,
            values=["Classic", "Dark"],
            state="readonly",
        )
        theme_combobox.bind("<<ComboboxSelected>>", self.update_theme)
        theme_combobox.grid(row=1, column=0, padx=padx, pady=pady)

        credits_btn = tk.Button(
            self.tabs_settings,
            text="Credits",
            command=lambda: tk.messagebox.showinfo(
                title="Credits",
                message="%s by %s\n\nIcons:\n%s" % (
                    self.master.title(),
                    "Kekalainen ([email protected])",
                    "Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0)",
                ),
            ),
        )
        credits_btn.grid(row=2, column=0, padx=padx, pady=pady, sticky="NW")

        quit_btn = tk.Button(self, text="Quit", command=self.master.destroy)
        quit_btn.grid(row=1, column=0, padx=padx, pady=pady, sticky="NW")

        self.grid()

    def import_pgn(self):
        path = filedialog.askopenfilename(
            title="Import a PGN file",
            filetypes=[("PGN file", "*.pgn")],
        )
        if path:
            with open(path) as f:
                self.pgn_text.delete(1.0, tk.END)
                self.pgn_text.insert(1.0, f.read())

    def export_pgn(self):
        path = filedialog.asksaveasfilename(
            title="Export a PGN file",
            filetypes=[("PGN file", "*.pgn")],
            defaultextension=".pgn",
        )
        if path:
            with open(path, "w") as f:
                f.write(self.pgn_text.get(1.0, tk.END))

    def db_save_game(self):
        name = simpledialog.askstring("Save PGN",
                                      "Enter a name for the game.",
                                      parent=self)
        if name:
            game = GameModel(name=name, pgn=self.moves_text.get(1.0, tk.END))
            self.db_session.add(game)
            self.db_session.commit()
            self.db_load_games()

    def db_load_games(self):
        self.db_games = (self.db_session.query(GameModel).order_by(
            GameModel.id.desc()).all())
        names = []
        for game in self.db_games:
            names.append(game.name)
        self.game_combobox.config(values=names)
        if names:
            self.game_combobox.set(names[0])
        else:
            self.game_combobox.set("")

    def db_load_pgn(self):
        if len(self.db_games) > 0:
            game = self.db_games[self.game_combobox.current()]
            self.pgn_text.delete(1.0, tk.END)
            self.pgn_text.insert(1.0, game.pgn)

    def db_delete_game(self):
        if len(self.db_games) > 0:
            game = self.db_games[self.game_combobox.current()]
            self.db_session.delete(game)
            self.db_session.commit()
            self.db_load_games()

    def db_get_setting(self, name, fallback):
        setting = (self.db_session.query(SettingModel).filter(
            SettingModel.name == name).first())
        if setting:
            return setting.value
        return fallback

    def db_store_setting(self, name, value):
        setting = (self.db_session.query(SettingModel).filter(
            SettingModel.name == name).first())
        if setting:
            setting.value = value
        else:
            setting = SettingModel(name=name, value=str(value))
        self.db_session.add(setting)
        self.db_session.commit()

    def play_move_sound(self, undo=False):
        """Plays a sound for a moving piece."""
        threading.Thread(
            target=playsound,
            args=("src/audio/move_" +
                  ("2" if (undo and not self.game.white_to_move) or
                   (not undo and self.game.white_to_move) else "1") +
                  ".mp3", ),
            daemon=True,
        ).start()

    def update_theme(self, event=None):
        """Stores the selected theme and updates the board, if necessary."""
        theme = self.theme.get()
        self.db_store_setting("theme", theme)
        if hasattr(self, "game"):
            colors = ["#542E1D", "#EFD8B0"]
            if theme == "Dark":
                colors = ["#9C9C9C", "#4A4A4A"]
            self.board_frame.tile_colors = colors
            self.board_frame.draw_board()

    def on_game_update(self):
        game_over_previously = "to move" not in self.status_label["text"]
        text = ""

        if self.game.check and not self.game.checkmate:
            text += "Check. "

        if self.game.white_to_move:
            text += "White to move."
        else:
            text += "Black to move."

        if self.game.checkmate:
            text = "Checkmate."
            if not self.game.white_to_move:
                text += " White wins."
            else:
                text += " Black wins."
        elif self.game.stalemate:
            text = "Stalemate. Draw."
        elif self.game.draw:
            text = "Draw."

        self.status_label["text"] = text

        move_log = ""
        for i in range(len(self.game.an_moves)):
            if i % 2 == 0:
                move_log += str(i // 2 + 1) + ". "
            move_log += self.game.an_moves[i]
            if i % 2 == 0:
                move_log += " "
            else:
                move_log += "\n"

        if self.game.checkmate or self.game.stalemate or self.game.draw:
            move_log = move_log[0:len(move_log) - 1] + " "
            if self.game.checkmate:
                if self.game.white_to_move:
                    move_log += "0-1"
                else:
                    move_log += "1-0"
            else:
                move_log += "1/2-1/2"

        self.moves_text.config(state=tk.NORMAL)
        self.moves_text.delete(1.0, tk.END)
        self.moves_text.insert(1.0, move_log)
        self.moves_text.config(state=tk.DISABLED)
        self.moves_text.yview(tk.END)

        if not self.game.draw and True in self.game.can_claim_draw:
            self.draw_btn.grid()
        else:
            self.draw_btn.grid_remove()

        if hasattr(self.game, "ai") and self.game.white_to_move:
            self.board_frame.draw_pieces()

        moves_length = len(self.game.an_moves)
        if self.enable_sounds.get(
        ) and self.previous_moves_length != moves_length:
            undo = self.previous_moves_length > moves_length
            if hasattr(self.game, "ai") and undo and not game_over_previously:
                self.play_move_sound(not undo)
            self.play_move_sound(undo)
            self.previous_moves_length = moves_length

    def on_promotion_piece_selected(self):
        if hasattr(self, "game"):
            self.game.board.promotion_piece = self.promotion_piece.get()

    def start_game(self, view_mode=False):
        if not hasattr(self, "game"):
            self.previous_moves_length = 0
            if view_mode:
                self.active_pgn = re.findall(
                    "((?!-)[a-zA-Z0-]+[0-9]?\w+(?!\.)=?[N|B|R|Q]?)(?![^{]*})(?![^[]*])",
                    self.pgn_text.get(1.0, tk.END),
                )
                if not self.active_pgn:
                    return
                self.active_pgn_index = 0
                self.previous_move_btn.configure(state=tk.DISABLED)
                self.next_move_btn.configure(state=tk.NORMAL)
                self.view_control_btn_frame.grid()
                self.tabs.select(self.tabs_game)
            else:
                self.promotion_piece_selection_frame.grid()
                self.save_game_btn.grid()

            self.game = Game(
                on_update=self.on_game_update,
                ai_difficulty=self.ai_difficulty.get()
                if not view_mode else -1,
            )
            self.game.board.promotion_piece = self.promotion_piece.get()
            self.board_dimension = self.game.board.width * self.board_tile_width
            self.board_window = tk.Toplevel(master=self)
            x = self.master.winfo_x() - self.board_dimension - 4
            y = self.master.winfo_y()
            self.board_window.geometry(
                "%dx%d+%d+%d" %
                (self.board_dimension, self.board_dimension, x, y))
            self.board_window.resizable(False, False)
            self.board_frame = BoardFrame(
                self.board_window,
                game=self.game,
                tile_width=self.board_tile_width,
                view_mode=view_mode,
            )
            self.update_theme()
            self.master.bind("<Configure>", self.board_window_follow)
            self.board_window.protocol("WM_DELETE_WINDOW",
                                       self.on_board_window_close)

            self.start_frame.grid_remove()
            self.status_frame.grid()
            self.on_game_update()

    def claim_draw(self):
        if hasattr(self, "game"):
            if self.game.claim_draw():
                self.board_frame.deselect_tile()
                self.draw_btn.grid_remove()

    def next_move(self):
        n = len(self.active_pgn)
        if self.active_pgn_index < n:
            self.game.move_piece_an(self.active_pgn[self.active_pgn_index])
            self.board_frame.draw_pieces()
            self.active_pgn_index += 1
            if self.active_pgn_index == n:
                self.next_move_btn.configure(state=tk.DISABLED)
            self.previous_move_btn.configure(state=tk.NORMAL)

    def previous_move(self):
        if self.active_pgn_index > 0:
            self.game.undo_move()
            self.board_frame.draw_pieces()
            self.active_pgn_index -= 1
            if self.active_pgn_index == 0:
                self.previous_move_btn.configure(state=tk.DISABLED)
            self.next_move_btn.configure(state=tk.NORMAL)

    def board_window_follow(self, event=None):
        x = self.master.winfo_x() - self.board_dimension - 4
        y = self.master.winfo_y()
        self.board_window.geometry("+%d+%d" % (x, y))

    def on_board_window_close(self):
        delattr(self, "game")
        self.master.unbind("<Configure>")
        self.board_window.destroy()
        self.start_frame.grid()
        self.status_frame.grid_remove()
        self.view_control_btn_frame.grid_remove()
        self.promotion_piece_selection_frame.grid_remove()
        self.save_game_btn.grid_remove()
        self.draw_btn.grid_remove()
コード例 #27
0
ファイル: console_widget.py プロジェクト: parklez/twitch-bot
class Console(tkinter.Frame):

    def __init__(self, parent, settings, max_lines=200, **kwargs):
        super().__init__(parent, **kwargs)

        self.settings = settings
        self.max_lines = max_lines
        self.console = ScrolledText(self,
                                    bg=Theme.CONSOLE_BG,
                                    highlightbackground=Theme.BG,
                                    highlightcolor=Theme.BG,
                                    wrap=tkinter.CHAR,
                                    width=40,
                                    height=10,
                                    state='disabled',
                                    relief='flat')

        # Despite setting height above, this widget gets expanded fully,
        # if the canvas is smaller than the height, will look odd.
        self.console.pack(fill=tkinter.BOTH,
                          expand=True)

        self.font = ('Helvetica', 11, 'bold')

        # Text color
        self.console.tag_config('TEXT',
                                foreground=Theme.CONSOLE_TEXT,
                                font=('Helvetica', 11),
                                spacing1=5,
                                spacing3=5)

        self.console.tag_config('TEXT_ALT',
                                foreground=Theme.CONSOLE_TEXT,
                                background=Theme.CONSOLE_BG_ALT,
                                selectbackground='SystemHighlight',
                                font=('Helvetica', 11),
                                spacing1=5,
                                spacing3=5)
        # Why does setting 'background' causes highlighted text color to be transparent?
        # https://web.archive.org/web/20201112014139id_/https://effbot.org/tkinterbook/tkinter-widget-styling.htm
        self.alt_bg = False

        # Logging colors
        self.console.tag_config('INFO', foreground=Theme.LOG_INFO)
        self.console.tag_config('DEBUG', foreground=Theme.LOG_DEBUG)
        self.console.tag_config('ERROR', foreground=Theme.LOG_ERROR)
        self.console.tag_config('WARNING', foreground=Theme.LOG_WARNING)
        self.console.tag_config('CRITICAL', foreground=Theme.LOG_CRITICAL)
        self.console.focus()

        if not self.settings['irc']['username']:
            self.welcome()
        self.after(100, self.pooling)

    def pooling(self):
        while 1:
            try:
                message = QUEUE.get(block=False)
                self.insert(message)
            except queue.Empty:
                break
        self.after(100, self.pooling)

    def insert(self, text):
        self.console.configure(state='normal') # Allow writing
        try: # Tcl can't render some characters
            if isinstance(text, Message):
                self.alt_bg = not self.alt_bg
                user_color = 'lightblue1' if not text.tags.get('color') else text.tags.get('color')
                username_tag = f'{text.sender}{"alt_bg" if self.alt_bg else ""}'
                self.console.tag_config(username_tag,
                                        font=self.font,
                                        foreground=user_color,
                                        background=Theme.CONSOLE_BG_ALT if self.alt_bg else Theme.CONSOLE_BG,
                                        selectbackground='SystemHighlight',
                                        spacing1=5,
                                        spacing3=5)
                self.console.insert(tkinter.END, text.sender, username_tag)
                self.console.insert(tkinter.END, f': {text.message}\n', 'TEXT_ALT' if self.alt_bg else 'TEXT')
            else:
                message = LOGGER.handlers[1].format(text) # This is not a good way to access this
                self.console.insert(tkinter.END, f'{message}\n', text.levelname)

        except tkinter.TclError as e:
            if isinstance(text, Message):
                # Replace every char outside of Tcl's allowed range with the ? char.
                text.message = ''.join((ch if ord(ch) <= 0xFFFF else '\uFFFD') for ch in text.message)
                self.console.insert(tkinter.END, f': {text.message}\n', 'TEXT')

            else:
                self.console.insert(tkinter.END, f'{e}\n', 'ERROR')

        #https://stackoverflow.com/questions/4609382/getting-the-total-number-of-lines-in-a-tkinter-text-widget
        self.line_count = int(self.console.index('end-2c').split('.')[0])
        if self.line_count > self.max_lines:
            self.console.delete(1.0, 2.0)

        self.console.configure(state='disabled') # Disallow writing
        self.console.yview(tkinter.END)

    def welcome(self):
        self.font = ('TkDefaultFont', 11, 'bold')
        self.console.tag_configure('lightblue', foreground='lightblue1', font=self.font, justify='center')
        self.console.tag_configure('white', foreground='white', font=self.font)
        self.console.tag_configure('orange', foreground='orange', font=self.font)
        self.console.tag_configure('pink', foreground='#FFC8D7', font=self.font)
        self.console.tag_configure('red', foreground='red', font=self.font, spacing1=2, spacing3=2)
        self.console.tag_config('grey', foreground='grey', font=('TkDefaultFont', 8, 'bold'))

        self.console.configure(state='normal')
        self.console.insert(tkinter.END, '~ Welcome to parky\'s twitch bot! ~\n\n', 'lightblue')
        self.console.insert(tkinter.END, '\n', 'white')
        self.console.insert(tkinter.END, 'Quick setup:\n', 'orange')
        self.console.insert(tkinter.END, '\n', 'white')
        self.console.insert(tkinter.END, '1', 'red')
        self.console.insert(tkinter.END, '. Click on the "', 'white')

        self.settings_img = tkinter.PhotoImage(data=Theme.SETTINGS_ICON)
        self.console.image_create(tkinter.END, image=self.settings_img)

        self.console.insert(tkinter.END, '" button.\n', 'white')
        self.console.insert(tkinter.END, '2', 'red')
        self.console.insert(tkinter.END, '. Fill in IRC fields to gain chat access!\n', 'white')
        self.console.insert(tkinter.END, '3', 'red')
        self.console.insert(tkinter.END, '. ', 'white')
        self.console.insert(tkinter.END, 'Fill in Twitch API to gain access to channel metadata, such as current title, game, uptime, followers... ', 'white')
        self.console.insert(tkinter.END, '(optional)\n', 'grey')
        self.console.insert(tkinter.END, '\n', 'TEXT')

        self.console.configure(state='disabled')
コード例 #28
0
class FrontWindow:
    def __init__(self, root, port):
        self.root = root
        self.port = port

        self.Frame = tk.Frame(self.root, height=600, width=700)
        self.Frame.pack(side=tk.RIGHT)

        self.textField = ScrolledText(self.Frame)
        self.textField.place(relx=0.05, rely=0.05, height=525, width=350)

        self.statusLabel = tk.Label(self.Frame)

        self.combobox = ttk.Combobox(self.Frame)
        self.spinbox = tk.Spinbox(self.Frame,
                                  from_=1.0,
                                  to=10.0,
                                  increment=0.5)
        self.commandInput = tk.Entry(self.Frame)
        self.ending = tk.IntVar()

        self.openClosePortButton = tk.Button(self.Frame)

    def addPortCombobox(self):
        self.combobox['font'] = ('Arial', 14)
        self.combobox['state'] = 'readonly'
        self.combobox['values'] = ('COM1', 'COM2', 'COM3', 'COM4', 'COM5',
                                   'COM6', 'COM7', 'COM8')
        self.combobox.current(2)
        self.combobox.place(relx=0.8, rely=0.05, width=100)

    def addPortSpinbox(self):
        defaultValue = tk.StringVar()
        defaultValue.set('5.0')

        self.spinbox['textvariable'] = defaultValue
        self.spinbox['font'] = ('Arial', 14)
        self.spinbox['state'] = 'readonly'

        self.spinbox.place(relx=0.8, rely=0.15, width=100)

    def addCommandInputField(self):
        self.commandInput['font'] = ('Arial', 14)
        self.commandInput.place(relx=0.55, rely=0.65, width=200)

    def addCheckbutton(self):
        checkbutton = tk.Checkbutton(self.Frame,
                                     text='Adjust CR+LF',
                                     font=('Arial', 13),
                                     variable=self.ending)

        checkbutton.place(relx=0.55, rely=0.7)

    # labels
    def addStatusLabel(self):
        self.statusLabel.destroy()

        if self.port.is_open:
            labelText = 'opened'
            color = 'green'
        else:
            labelText = 'closed'
            color = 'red'

        self.statusLabel = tk.Label(self.Frame,
                                    font=('Arial', 15),
                                    text=labelText,
                                    fg=color)
        self.statusLabel.place(relx=0.8, rely=0.36)

    def addPortNameLabel(self):
        portNameLabel = tk.Label(self.Frame,
                                 font=('Arial', 15),
                                 text='Port name: ')
        portNameLabel.place(relx=0.6, rely=0.05)

    def addPortTimeoutLabel(self):
        portTimeoutLabel = tk.Label(self.Frame,
                                    font=('Arial', 15),
                                    text='Port timeout: ')
        portTimeoutLabel.place(relx=0.58, rely=0.15)

    def addPortStatusLabel(self):
        portStatusLabel = tk.Label(self.Frame,
                                   font=('Arial', 15),
                                   text='Port status: ')
        portStatusLabel.place(relx=0.6, rely=0.36)

    def addCommandLabel(self):
        commandLabel = tk.Label(self.Frame,
                                font=('Arial', 15),
                                text='Insert command: ')
        commandLabel.place(relx=0.58, rely=0.59)

    # buttons callbacks
    def callbackOptionsBtn(self):
        self.port.port = str(self.combobox.get())
        OptionsWindow(self.root, self.port)

    def callbackOpenClosePortBtn(self):
        if not self.port.is_open:
            self.port.port = str(self.combobox.get())
            self.port.timeout = float(self.spinbox.get())

            try:
                self.port.open()
            except serial.serialutil.SerialException as e:
                print(e)
                errorMsg = 'Could not open port: ' + str(self.port.port)
                messagebox.showinfo('Error', errorMsg)
                return

            status = 'Close port'

        else:
            try:
                self.port.close()
            except serial.serialutil.SerialException as e:
                print(e)
                errorMsg = 'Could not close port: ' + str(self.port.port)
                messagebox.showinfo('Error', errorMsg)
                return

            status = 'Open port'

        self.openClosePortButton.config(text=status)
        self.addStatusLabel()

    def getInputFromPort(self):
        wasLastStringEmpty = True

        if self.port.is_open:
            timeout = float(self.spinbox.get())
            start = time.time()
            while True:
                inputFromPort = self.port.readline()

                if inputFromPort == b'':
                    if wasLastStringEmpty:
                        if time.time() - start >= timeout:
                            infoMsg = 'Timeout expired'
                            messagebox.showinfo('Message', infoMsg)
                            break
                        else:
                            continue
                    else:
                        break
                else:
                    wasLastStringEmpty = False

                self.textField.insert(tk.END, inputFromPort)
                self.textField.yview(tk.END)
                self.root.update()
        else:
            errorMsg = 'Port ' + str(self.combobox.get()) + ' is not open!'
            messagebox.showinfo('Error', errorMsg)

    def writeToPort(self):
        if self.port.is_open:
            command = self.commandInput.get()

            if self.ending.get():
                command += chr(13) + chr(10)

            self.port.write(command.encode('utf-8'))
            self.commandInput.delete(0, 'end')
        else:
            errorMsg = 'Port ' + str(self.combobox.get()) + ' is not open!'
            messagebox.showinfo('Error', errorMsg)

    def callbackSaveBtn(self):
        fileTypes = (('text files', '*.txt'), ('all files', '*.*'))
        filename = filedialog.asksaveasfilename(title='Select file',
                                                filetypes=fileTypes)

        try:
            txtFile = open(filename, 'w+')
        except FileNotFoundError as e:
            print(e)
            return

        txtFile.write(self.textField.get('1.0', tk.END))

        txtFile.close()

    # buttons definitions
    def addOptionsButton(self):
        optionsButton = tk.Button(self.Frame,
                                  text='More options',
                                  font=('Arial', 15),
                                  command=self.callbackOptionsBtn)

        optionsButton.place(relx=0.67, rely=0.23, width=150)

    def addOpenClosePortButton(self):
        self.openClosePortButton['text'] = 'Open Port'
        self.openClosePortButton['font'] = ('Arial', 15)
        self.openClosePortButton['command'] = self.callbackOpenClosePortBtn

        self.openClosePortButton.place(relx=0.67, rely=0.45, width=150)

    def addReadFromPortButton(self):
        readFromPortButton = tk.Button(self.Frame,
                                       text='Read',
                                       font=('Arial', 15),
                                       command=self.getInputFromPort)

        readFromPortButton.place(relx=0.7, rely=0.77, width=100)

    def addWriteToPortButton(self):
        writeToPortButton = tk.Button(self.Frame,
                                      text='Write',
                                      font=('Arial', 15),
                                      command=self.writeToPort)

        writeToPortButton.place(relx=0.85, rely=0.64, width=100)

    def addSaveButton(self):
        saveButton = tk.Button(self.Frame,
                               font=('Arial', 15),
                               text='Save',
                               command=self.callbackSaveBtn)

        saveButton.place(relx=0.6, rely=0.9, width=100)

    def addExitButton(self):
        exitButton = tk.Button(self.Frame,
                               text='Exit',
                               font=('Arial', 15),
                               command=lambda: self.root.destroy())

        exitButton.place(relx=0.8, rely=0.9, width=100)
コード例 #29
0
class TkGraphicInterface:
    def __init__(self, on_stop=Callable[[None], None]):
        self._on_stop = on_stop

        self._thread = None

        self._ui_ready = False
        self._logger_buffer = list()

        self._window = None
        self._logger_widget = None

        self._connected = False
        self._client_name = False

    def start_ui(self):
        self._thread = threading.Thread(target=self._run_ui)
        self._thread.start()

    def kill_ui(self):
        self._window.destroy()
        self._window = None
        self._thread.join()

    def on_emit_log(self, message: str):
        if not self._ui_ready:
            self._logger_buffer.append(message)
        elif len(self._logger_buffer) > 0:
            self._logger_buffer.append(message)
            for x in self._logger_buffer:
                self._update_logger(x)
            self._logger_buffer.clear()
        else:
            self._update_logger(message)

    # noinspection PyTypeChecker
    def on_update_status(self, state: Tuple[bool, str]):
        if self._connected == state[0] or self._client_name == state[1]:
            pass

        self._update_status(state[0], state[1])

    def _run_ui(self):
        self._init_ui()
        self._window.mainloop()

    def _init_ui(self):
        self._window = tkinter.Tk()
        self._window.tk.call('tk', 'scaling', 4.0)
        self._window.title("VFT Device Server")
        self._window.geometry("600x400+100+100")

        print(font.families())

        head_label = tkinter.Label(
            self._window,
            text="VFT Device Server",
            font=font.Font(family="fixed", size=30),
        )
        head_label.grid(row=0, column=0)

        version_label = tkinter.Label(
            self._window,
            text="GUI version 1.0",
        )
        version_label.grid(row=0, column=1)

        self._logger_widget = ScrolledText(
            self._window,
            state="disabled",
            font="TkFixedFont",
            width=83,
            height=16,
        )
        self._logger_widget.place(x=0, y=200)

        self._ui_ready = True

        self.on_emit_log("[o] tkinter-ui ready.")

    def _update_status(self, connected: bool, client_name: str):
        pass

    def _update_logger(self, message: str):
        self._logger_widget.configure(state="normal")
        self._logger_widget.insert(tkinter.END, message + "\n")
        self._logger_widget.configure(state="disabled")
        self._logger_widget.yview(tkinter.END)

    def _stop_server(self):
        self.kill_ui()
コード例 #30
0
class NamedWindow(object):
    """
  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 = tkinter.font.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" % (old_div(rgb[0], 256), old_div(
            rgb[1], 256), old_div(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 list(fg_color_codes.keys()):
            color = self.convertColor(fg_color_codes[ck])
            self._txt.tag_config(ck, foreground=color)

        for ck in list(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) == tuple:
            msg = msg[0]

        if type(msg) == bytes:
            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()
コード例 #31
0
ファイル: client.py プロジェクト: eviebrock/git
class clientUI():
	def __init__(self, args, q_send, q_receive_join, q_receive_text, q_receive_leave, b):
		self.first_click = True;
		self.args = args
		self.q_send = q_send
		self.q_receive_join = q_receive_join
		self.q_receive_text = q_receive_text
		self.q_receive_leave = q_receive_leave
		self.b = b
		
	def start(self):
		print("Starting clientUI...")
		self.initDisplay()
		self.ui_messages.insert(tkinter.END, "%s has joined the chat room...\n" % self.args.username)
		self.ui_input.insert(tkinter.END, "<Enter message>")

		self.ui_top.after(100, self.receiveMsg)

		# This call to mainloop() is blocking and will last for the lifetime
		# of the GUI.
		self.ui_top.mainloop()

		# Should only get here after destroy() is called on ui_top
		print("Stopping clientUI...")

	def initDisplay(self):
		self.ui_top = tkinter.Tk()
		self.ui_top.wm_title("Chat Room 1.0 - %s" % self.args.username)
		self.ui_top.resizable('1','1')
		self.ui_top.protocol("WM_DELETE_WINDOW", self.eventDeleteDisplay)

		self.ui_messages = ScrolledText(
			master=self.ui_top,
			wrap=tkinter.WORD,
			width=50,  # In chars
			height=25)  # In chars     

		self.ui_input = tkinter.Text(
			master=self.ui_top,
			wrap=tkinter.WORD,
			width=50,
			height=4)
        
		# Bind the button-1 click of the Entry to the handler
		self.ui_input.bind('<Button-1>', self.eventInputClick)
        
        	#self.ui_top.after(200, receiveMsg)
        
		self.ui_button_send = tkinter.Button(
			master=self.ui_top,
			text="Send",
			command=self.sendMsg)

		# Compute display position for all objects
		self.ui_messages.pack(side=tkinter.TOP, fill=tkinter.BOTH)
		self.ui_input.pack(side=tkinter.TOP, fill=tkinter.BOTH)
		self.ui_button_send.pack(side=tkinter.LEFT)

	# SEND button pressed
	def sendMsg(self):
		# Get user input (minus newline character at end)
		msg = self.ui_input.get("0.0", tkinter.END+"-1c")
		if len(msg) > 0:
			self.q_send.put(msg)
			print("UI: Got text: '%s'" % msg)

			# Add this data to the message window
			self.ui_messages.insert(tkinter.INSERT, "%s: %s\n" % (self.args.username, msg))
			self.ui_messages.yview(tkinter.END)  # Auto-scrolling

			# Clean out input field for new data
			self.ui_input.delete("0.0", tkinter.END)

	# Receive messages from other clients
	def receiveMsg(self):
		#print ("Inside receiveMsg")
		try:
			username_join = self.q_receive_join.get(block=False)
			join_msg = True;
		except queue.Empty:
			join_msg = False;
			
		try:
			username_text, text = self.q_receive_text.get(block=False)
			text_msg = True;
		except queue.Empty:
			text_msg = False;
		
		try:
			username_leave = self.q_receive_leave.get(block=False)
			leave_msg = True;
		except queue.Empty:
			leave_msg = False;
		
		if join_msg:
			self.ui_messages.insert(tkinter.INSERT, "%s has joined the chat room...\n" % username_join)
			self.ui_messages.yview(tkinter.END)  # Auto-scrolling
			
		elif text_msg:
			self.ui_messages.insert(tkinter.INSERT, "%s: %s\n" % (username_text, text))
			self.ui_messages.yview(tkinter.END)  # Auto-scrolling
		
		elif leave_msg: 
			self.ui_messages.insert(tkinter.INSERT, "%s has left the chat room...\n" % username_leave)
			self.ui_messages.yview(tkinter.END)  # Auto-scrolling
			
		self.ui_top.after(100, self.receiveMsg)

	# FILE button pressed
	def sendFile(self):
		file = askopenfilename()

		if(len(file) > 0 and os.path.isfile(file)):
			print("UI: Selected file: %s" % file)
		else:
			print("UI: File operation canceled")

	# Event handler - User closed program via window manager or CTRL-C
	def eventDeleteDisplay(self):
		print("UI: Closing")
		global client_active
		client_active = False;
		
		# Continuing closing window now
		self.ui_top.destroy()

	# Event handler - User clicked inside the "ui_input" field
	def eventInputClick(self, event):
		if(self.first_click):
			# If this is the first time the user clicked,
			# clear out the tutorial message currently in the box.
			# Otherwise, ignore it.
			self.ui_input.delete("0.0", tkinter.END)
			self.first_click = False;
コード例 #32
0
class ConsoleUi:
    """Poll messages from a logging queue and display them in a scrolled text widget"""
    def __init__(self, frame):
        self.frame = frame

        # Create a ScrolledText wdiget
        self.scrolled_text = ScrolledText(frame, state='disabled', height=12)
        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
        self.scrolled_text.configure(font='TkFixedFont')
        self.scrolled_text.tag_config('INFO', foreground='black')
        self.scrolled_text.tag_config('DEBUG', foreground='gray')
        self.scrolled_text.tag_config('WARNING', foreground='orange')
        self.scrolled_text.tag_config('ERROR', foreground='red')
        self.scrolled_text.tag_config('CRITICAL',
                                      foreground='red',
                                      underline=1)
        self.scrolled_text.tag_config(
            'COPYOVER',
            foreground='blue',
        )
        self.scrolled_text.tag_config(
            'COPYNEW',
            foreground='green',
        )
        self.scrolled_text.tag_config(
            'DELETE',
            foreground='red',
        )
        self.scrolled_text.tag_config(
            'MOVE',
            foreground='magenta',
        )

        # Start polling messages from the queue
        self.frame.after(100, self.poll_log_queue)

    def display(self, record):
        msg = record
        # Send special message to clear the log
        if msg == "__clear__":
            self.scrolled_text.configure(state='normal')
            self.scrolled_text.delete(1.0, tk.END)
            self.scrolled_text.configure(state='disabled')
            return

        self.scrolled_text.configure(state='normal')
        self.scrolled_text.insert(tk.END, msg[1] + '\n', msg[0])
        self.scrolled_text.configure(state='disabled')

        # Autoscroll to the bottom
        self.scrolled_text.yview(tk.END)

    def poll_log_queue(self):
        # Check every 100ms if there is a new message in the queue to display
        while True:
            try:
                record = msg_queue.get(block=False)
            except queue.Empty:
                break
            else:
                self.display(record)
        self.frame.after(100, self.poll_log_queue)
コード例 #33
0
class ChatWindow(Tk):
    def __init__(self, sock=None, peer=None, address=None):
        failure = None

        self.peer = Peer()
        if peer:
            self.peer.host, self.peer.port = peer

        self.nick = 'me'
        self.mode = Mode.msgpack
        self.sent_header = False
        self.address = address

        if sock:
            sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)

            self.peer.sock = sock
            self.initiator = False

            header = self.peer.recv(5)
            if header[1:] != b'FLEX':
                Socket.abort(self.peer.sock,
                             (b'Unrecognized protocol header\n'))
                print('Unrecognized protocol:', header)
                sys.exit(0)

            if header[0] == 0:
                self.mode = Mode.text
            elif header[0] == 0xa4:
                self.mode = Mode.msgpack
            elif header[0] == 0x22:
                self.mode = Mode.json
            else:
                Socket.abort(self.peer.sock, (b'Unrecognized protocol mode\n'))
                print('Unrecognized protocol mode:', header[0])
                sys.exit(0)

        elif peer:
            self.initiator = True
            try:
                self.connect()
            except Exception as e:
                failure = str(e)

        else:
            raise Exception("Missing required parameter")

        Tk.__init__(self)
        self.title(self.peer.name)

        #self.root = Tk()
        #self.main = Frame(self.root)
        self.main = Frame(self)
        self.main.pack(expand=True, fill=BOTH)

        self.chat_Text = ScrolledText(self.main)
        self.chat_Text.pack(expand=True, fill=BOTH)
        self.chat_Text['height'] = 10
        self.chat_Hyperlink = Hyperlink(self.chat_Text)

        self.send_Frame = Frame(self.main)
        self.send_Frame.pack(fill=X)

        self.send_Text = Text(self.send_Frame)
        self.send_Text.pack(side=LEFT, expand=True, fill=X)
        self.send_Text['height'] = 2
        self.send_Text.bind('<Shift-Return>', self.send_Newline)
        self.send_Text.bind('<Control-Return>', self.send_Newline)
        self.send_Text.bind('<Return>', self.send_Action)
        self.send_Button = Button(self.send_Frame,
                                  text='Send',
                                  command=self.send_Action)
        self.send_Button.pack(side=LEFT)

        self.status_Label = Label(self.main,
                                  text='Peer: {}'.format(self.peer.name))
        self.status_Label.pack()

        self.send_Text.focus()

        if failure:
            self.disable(failure)
        else:
            try:  #this only works in linux for some reason
                self.checker = None
                self.tk.createfilehandler(self.peer.sock, _tkinter.READABLE,
                                          self.eventChecker)

            except:  #rescue windows
                traceback.print_exc()
                print('Windows mode!')
                sock.setblocking(False)
                self.checker = self.main.after(100, self.eventChecker)

    @property
    def mode(self):
        return self.receive_mode

    @mode.setter
    def mode(self, mode):
        self.receive_mode = mode
        self.send_mode = mode

    @property
    def receive_mode(self):
        return self.receive_proto.mode

    @receive_mode.setter
    def receive_mode(self, mode):
        if mode == Mode.msgpack:
            self.receive_proto = Msgpack()
        elif mode == Mode.json:
            self.receive_proto = JSON()
        elif mode == Mode.text:
            self.receive_proto = PText()
        else:
            raise ValueError('Unknown protocol mode: {}'.format(mode))

    @property
    def send_mode(self):
        return self.send_proto.mode

    @send_mode.setter
    def send_mode(self, mode):
        if mode == Mode.msgpack:
            self.send_proto = Msgpack()
        elif mode == Mode.json:
            self.send_proto = JSON()
        elif mode == Mode.text:
            self.send_proto = PText()
        else:
            raise ValueError('Unknown protocol mode: {}'.format(mode))

    def send_Newline(self, *args):
        # Let the default handler make a newline. This exists
        # just to prevent the send_Action handler from activating
        pass

    def destroy(self):
        Tk.destroy(self)

    def append_text(self, text):
        scroll = self.chat_Text.yview()[1]

        # find hyperlinks and link them
        i = text.find('http://')
        if i < 0: i = text.find('https://')

        if i >= 0:
            self.append_text(text[:i])
            text = text[i:]

            # find the end of the link text
            i = text.find(' ')
            j = text.find('\n')

            if i < 0:
                i = j
            elif i >= 0 and j >= 0:
                i = min(i, j)

            if i >= 0:
                self.chat_Hyperlink.add(END, text[:i])
                self.append_text(text[i:])
            else:
                self.chat_Hyperlink.add(END, text)

        else:
            self.chat_Text.insert(END, text)

        if scroll >= 0.99:
            self.chat_Text.yview_moveto(1.0)

    def send_Action(self, *args):
        if not self.peer.sock: return 'break'

        text = self.send_Text.get('1.0', END)
        text = text.strip()

        self.send_Text.delete('1.0', END)

        if not text: return 'break'

        # /me is a "social command", so it's exempt from command processing
        if text[0] == '/' and not text.startswith('/me '):
            if text == '/bye':
                self.send_command('BYE ')
            elif text.startswith('/nick'):
                name = text[6:]
                if len(name):
                    self.send_command('NICK', data=name)
                    self.nick = name
                    self.append_text('You are now known as {}\n'.format(name))
            elif text == '/text':
                self.send_command('TEXT')
                self.send_mode = Mode.text
                self.send_header_once()
            elif text == '/json':
                self.send_command('JSON')
                self.send_mode = Mode.json
                self.send_header_once()
            elif text == '/msgpack':
                self.send_command('MPCK')
                self.send_mode = Mode.msgpack
                self.send_header_once()
            else:
                self.append_text('Unrecognized command: {}\n'.format(text))
        else:
            self.append_text('{} {}: {}\n'.format(timestamp(), self.nick,
                                                  text))

            msg = self.send_proto.message(text,
                                          to=self.peer.name,
                                          From=str(self.address or ''))

            if _test_fragment:
                t = len(msg)
                h = t // 2

                self.peer.sendall(msg[:h])
                time.sleep(0.1)
                self.peer.sendall(msg[h:])
            else:
                self.peer.sendall(msg)

        # Prevent default handler from adding a newline to the input textbox
        return 'break'

    def send_command(self, cmd, data=None):
        message = self.send_proto.command(cmd, data=data)
        self.peer.sendall(message)

    def send_header_once(self):
        if not self.sent_header and self.initiator:
            self.send_header()
            self.sent_header = True

    def send_header(self):
        data = {
            'to': self.peer.name,
            'from': str(self.address),
            'options': [],
        }

        p = self.send_proto.header(data)
        if p is not None:
            self.peer.sendall(p)

    def update_peer_address(self, addr):
        self.peer.name = addr
        self.status_Label['text'] = 'Peer: ' + addr

    def process_header(self, header):
        self.update_peer_address(header['from'])

    def process_message(self, message):
        if 'to' in message and 'msg' not in message:
            self.process_header(message)

        elif 'cmd' in message:
            print('command:', message['cmd'], message['payload'])
            cmd = message['cmd']
            self.process_command(cmd, more=message['payload'])

        else:
            if message['from']:
                self.update_peer_address(message['from'])

            self.append_text('{} {}: {}\n'.format(timestamp(), self.peer.nick,
                                                  message['msg']))

    def process_command(self, cmd, more=None):
        if cmd == 'JSON':
            self.receive_mode = Mode.json

            if more:
                self.process_packet(more)

        elif cmd == 'MPCK':
            self.receive_mode = Mode.msgpack

            if more:
                self.process_packet(more)

        elif cmd == 'TEXT':
            self.receive_mode = Mode.text

        elif cmd.startswith('NICK'):
            oldnick = self.peer.nick
            if more:
                nick = more.strip()
            else:
                nick = cmd[4:].strip()

            if nick not in ('me', '', self.nick):
                self.peer.nick = nick
                self.append_text('{} is now known as {}\n'.format(
                    oldnick, self.peer.nick))
            else:
                self.append_text(
                    '{} tried to take the name {}, but that would be confusing.\n'
                    .format(oldnick, nick))

        elif cmd == 'BYE ':
            self.disable('Disconnecting: Bye\n')
            self.disconnect()

        else:
            self.append_text('Unrecognized command: {}'.format(cmd))

    def process_packet(self, packet):
        self.receive_proto.feed(packet)

        i = self.receive_proto.read()
        for o in i:
            self.process_message(o)

    def eventChecker(self, *args):  #could be (self, socket_fd, mask)
        try:
            try:
                packet = self.peer.recv(4096)
            except Exception as e:
                self.disable(str(e) + '\n')
                self.disconnect()
                traceback.print_exc()
                return

            print('packet:', packet, len(packet))
            if len(packet) == 0:
                self.disable('Disconnected\n')
                self.disconnect()
            else:
                self.process_packet(packet)
        finally:
            if self.checker != None:
                self.checker = self.main.after(100, self.eventChecker)

    def connect(self):
        self.peer.connect()

        header = self.send_proto.first_packet
        self.peer.send(header)
        self.send_header_once()

    def disconnect(self):
        self.tk.deletefilehandler(self.peer.sock)
        self.peer.sock.close()
        self.peer.sock = None

    def disable(self, message):
        self.append_text(timestamp() + ' ' + message)
        self.chat_Text.yview_moveto(1.0)
        self.send_Text.config(state='disabled')
        self.send_Button.config(state='disabled')

    @staticmethod
    def give_socket(sock):
        print("I got a socket:", sock)
        wnd = ChatWindow(sock=sock)
        wnd.main.mainloop()

    @staticmethod
    def new_chat(peer, address):
        print("New peer:", peer)
        wnd = ChatWindow(peer=peer, address=address)
        wnd.main.mainloop()
コード例 #34
0
class Console(tkinter.Frame):

    def __init__(self, parent, **kwargs):
        super().__init__(parent, **kwargs)

        self.console = ScrolledText(self,
                                    bg=Theme.CONSOLE_BG,
                                    wrap=tkinter.CHAR,
                                    width=40,
                                    height=10,
                                    state='disabled')

        # Despite setting height above, this widget gets expanded fully,
        # if the canvas is smaller than the height, will look odd.
        self.console.pack(fill=tkinter.BOTH,
                          expand=True)

        # Text color
        self.console.tag_config('TEXT', foreground=Theme.HL, font='bold')

        # Logging colors
        self.console.tag_config('INFO', foreground=Theme.LOG_INFO)
        self.console.tag_config('DEBUG', foreground=Theme.LOG_DEBUG)
        self.console.tag_config('ERROR', foreground=Theme.LOG_ERROR)
        self.console.tag_config('WARNING', foreground=Theme.LOG_WARNING)
        self.console.tag_config('CRITICAL', foreground=Theme.LOG_CRITICAL)
        self.console.focus()
        self.after(100, self.pooling)

    def pooling(self):
        while 1:
            try:
                message = QUEUE.get(block=False)
                self.insert(message)
            except queue.Empty:
                break
        self.after(100, self.pooling)

    def insert(self, text):
        self.console.configure(state='normal') # Allow writing
        try: # Tcl can't render some characters
            if isinstance(text, Message):
                self.console.tag_config(text.sender,
                                        font='bold',
                                        foreground=text.tags.get('color', 'lightblue1'))
                self.console.insert(tkinter.END, text.sender, text.sender)
                self.console.insert(tkinter.END, f': {text.message}\n', 'TEXT')
            else:
                message = LOGGER.handlers[1].format(text) # This is not a good way to access this
                self.console.insert(tkinter.END, f'{message}\n', text.levelname)

        except tkinter.TclError as e:
            if isinstance(text, Message):
                # Replace every char outside of Tcl's allowed range with the ? char.
                text.message = ''.join((ch if ord(ch) <= 0xFFFF else '\uFFFD') for ch in text.message)
                self.console.insert(tkinter.END, f': {text.message}\n', 'TEXT')

            else:
                self.console.insert(tkinter.END, f'{e}\n', 'ERROR')

        self.console.configure(state='disabled') # Disallow writing
        self.console.yview(tkinter.END)