LoginSignup
1
3

More than 5 years have passed since last update.

Python で独立したダイアローグボックスプロセスと通信をやってみる

Last updated at Posted at 2018-05-06

はじめに

独立したプロセス間通信の応用例として、ダイアローグボックスを表示するプロセスとの通信をやってみました。
ダイアローグボックスを表示するプロセス(dialogsrv)は、表示を要求するプロセス(dialogcli)からの要求を待ちます。そして、依頼された文字列を表示して、入力待ちになります。文字列入力後、'ok'ボタンをクリックされると入力された文字列をdialogcliへ返します。もし、'cancel'をクリックされた場合には、文字コード'\18'を返します。
dialogcliから文字コード'\04'をdialogsrvへ送ることにより、dialogsrvは処理を終了します。

具体的に

ダイアローグの表示には、tkinterを使用しています。

ダイアローグを表示するプロセス

ダイアログを表示するプロセスは、起動されるとダイアローグを作成した後、ソケット通信で表示要求を待ちます。表示要求が来るとその文字列をラベルに表示した後、root.mainloop()で入力待ちのループに入ります。
ダイアローグには、'ok'ボタンおよび'cancel'ボタンがクリックされた際の処理を宣言しており、それぞれのボタンに応じた処理を行ったのち、root.quit()で入力ループから抜けます。そして、次のソケット通信による要求待ちになります。
ソケット通信での要求時に、文字コード'\04'を受け取ると root.destroyでダイアローグを破棄して、プロセスを終了します。

dialogsrv.py

import multiprocessing      as mp
import tkinter              as tk
import tkinter.simpledialog as simpledialog
import tkinter.messagebox   as tkmsg
import time
from socket import socket, AF_INET, SOCK_STREAM

HOST        = 'localhost'
PORT        = 51000
MAX_MESSAGE = 2048
NUM_THREAD  = 4

CHR_CAN     = '\18'
CHR_EOT     = '\04'

class Dialog(mp.Process):

    #----------------------------------------------------
    def __init__(self):
        mp.Process.__init__(self)

    #----------------------------------------------------
    def send_result(self, mess):

        while True:
            try:
                # connect
                sock = socket(AF_INET, SOCK_STREAM)
                sock.connect((HOST, PORT + 1))

                # send message
                sock.send(mess.encode('utf-8'))

                # disconnect
                sock.close()
                break

            except:
                print ('retry: ' + mess)

    #----------------------------------------------------
    def showDialog(self, mess):

        self.root  = tk.Tk()
        self.root.title('scratch')
        self.root.minsize(width = 500, height = 250)

        self.frame = tk.Frame(self.root, width = 300, heigh = 200, bd = 11)
        self.frame.pack()

        self.label = tk.Label(self.frame, font = ("", 20), text = mess)
        self.label.grid(row = 0, column = 0, columnspan = 3, padx = 5, pady = 5)

        self.lbl1  = tk.Label(self.frame, font = ("", 20), text = '')
        self.lbl1.grid(row = 1, column = 0) 

        self.entry = tk.Entry(self.frame, font = ("", 20),  bd = 4)
        self.entry.grid(row = 2, column = 0, columnspan = 3, padx = 5, pady = 5)
        self.entry.focus()

        self.lbl2  = tk.Label(self.frame, font = ("", 20), text = '')
        self.lbl2.grid(row = 3, column = 0) 

        #+++++++++++++++++++++++++++++++++++
        def click():
            answer = self.entry.get()
            self.send_result(answer)
            self.root.quit()
            # self.root.destroy()
        self.button1 = tk.Button(self.frame,font = ("", 20),  width = 4, height = 1, text = 'ok', fg = "blue", command = click)
        self.button1.grid(row = 4, column = 0, sticky = tk.E ) 

        #+++++++++++++++++++++++++++++++++++
        def cancel():
            answer = CHR_CAN
            self.send_result(answer)
            self.root.quit()
            # self.root.destroy()
        self.button2 = tk.Button(self.frame,font = ("", 20),  width = 7, height = 1, text = 'cancel', fg = "red", command = cancel)
        self.button2.grid(row = 4, column = 2, sticky = tk.W) 

        # self.root.mainloop()

    #----------------------------------------------------
    def messDialog(self, mess):
        self.label.configure(text=mess)

    #----------------------------------------------------
    def loopDialog(self):
        self.root.focus()
        self.root.mainloop()

    #----------------------------------------------------
    def destroyDialog(self):
        self.root.destroy()

    #----------------------------------------------------
    def run(self):
        proc_name = self.name

        # connect
        sock = socket(AF_INET, SOCK_STREAM)
        sock.bind    ((HOST, PORT))
        sock.listen  (NUM_THREAD)
        print ("receiver ready, NUM_THREAD  = " + str(NUM_THREAD))

        self.showDialog('start of scratch dialog')

        # loop
        while True:
            try:
                conn, addr = sock.accept()
                mess       = conn.recv(MAX_MESSAGE).decode('utf-8')
                conn.close()

                # exit ?
                if (mess == CHR_EOT):
                    self.destroyDialog()
                    break

                # text
                self.messDialog(mess)
                self.loopDialog()

            except:
                print ('Error:' + mess)

        # disconnect
        sock.close()
        return

#----------------------------------------------------
def proc():
    # start dialog process
    dialog = Dialog()
    dialog.start()

    # wait for the end of process
    dialog.join()

if __name__ == '__main__':
    proc()

起動は、dialogsrv.proc()です。

ダイアローグへ表示を依頼するプロセス

ダイアローグへ文字列の表示要求をするプロセスは、表示する文字列を準備した後、ソケット通信を使って文字列を送信します。その後、ダイアローグからの応答を待ちます。
ここでは、簡単のため、10回のループで'message:n' (n:0~9)を表示しています。

dialogcli.py
import multiprocessing      as mp
import tkinter              as tk
import tkinter.simpledialog as simpledialog
import tkinter.messagebox   as tkmsg
import time

from socket import socket, AF_INET, SOCK_STREAM

HOST        = 'localhost'
PORT        = 51000
MAX_MESSAGE = 2048
NUM_THREAD  = 1

CHR_CAN     = '\18'
CHR_EOT     = '\04'

class DialogIF(mp.Process):

    #----------------------------------------------------
    def connect(self):
        # connect
        self.sock = socket(AF_INET, SOCK_STREAM)
        self.sock.bind    ((HOST, PORT + 1))
        self.sock.listen  (NUM_THREAD)
        print ("receiver ready, NUM_THREAD  = " + str(NUM_THREAD))

        return

    #----------------------------------------------------
    def dequeue(self):
        try:
            conn, addr = self.sock.accept()
            mess       = conn.recv(MAX_MESSAGE).decode('utf-8')
            conn.close()

            # cancel ?
            if (mess == CHR_CAN):
                print ('cancel')

            # text
            print ('text> ' + mess)

        except:
            print ('Error:' + mess)

        return mess

    #----------------------------------------------------
    def disconnect():
        self.sock.close()
        return

    #----------------------------------------------------
    def enqueue(self, mess):
        while True:
            try:
                # connect
                sock = socket(AF_INET, SOCK_STREAM)
                sock.connect((HOST, PORT))

                # send message
                sock.send(mess.encode('utf-8'))

                # disconnect
                sock.close()
                break

            except:
                print ('retry: ' + mess)

    #----------------------------------------------------
    def terminate(self):
        self.enqueue(CHR_EOT)

#----------------------------------------------------
def proc():
    dif = DialogIF()
    dif.connect()

    for i in range(10):
        dif.enqueue('message:' + str(i))
        r = dif.dequeue()
        if r is None:
            break

        if (r == CHR_CAN):
            print ('cancel')
        else:
            print ('result> ' + r)

    dif.terminate()

if __name__ == '__main__':
    proc()
1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3