前提・実現したいこと
pyqtgrafとtkinterのウィンドウを二つ同時に表示することは可能ですか?
可能であるならその方法を教えていただけると幸いです。
ちなみに、pyqtgrafは機器から得られたデータをリアルタイムでグラフ化、ファイル格納するプログラムで、tkinterは命令を表示するプログラムです。
発生している問題・エラーメッセージ
コマンドプロンプトで二つのファイルを同時に実行しようとすると下記のようなエラーが出ます。
sys:1: RuntimeWarning: Visible window deleted. To prevent this, store a reference to the window object.
試したこと
- コマンドプロンプトによるファイル同時実行
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
イベントループを別スレッドもしくは、別プロセスで実行することになります。
イベントループを独自に組めれば、双方を同一スレッド上で動かすことは可能です。
python
1 2def tk_event_loop(): # root.mainloop() を想定 3 while True: 4 print("tk") 5 6def qt_event_loop(): # app.exec_() を想定 7 while True: 8 print("qt") 9 10# 問題点: GUIライブラリはイベントループを持ちますが 11# 2つのループを同一スレッド上で実行は出来ない 12 13# 双方のイベントループを動かす独自のイベントループを実装する 14def my_event_loop(): 15 while True: 16 print("tk") # root.update() ... tk のイベント処理 17 print("qt") # app.processEvents() ... qt のイベント処理
同時にイベントループを稼働する方法は、終了時に同期を取る方法が難しい為、
別プロセスを検討した方が良さそうです。
python
1def tk_main(shared): 2 import tkinter as tk 3 from tkinter import ttk 4 from functools import partial 5 6 main_quit = partial(shared.queue.put, None) 7 8 root = tk.Tk() 9 button = ttk.Button(root, text="Quit") 10 button.config(command=main_quit) 11 button.pack() 12 13 root.protocol("WM_DELETE_WINDOW", main_quit) 14 15 root.mainloop() 16 17 18def qt_main(shared): 19 from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton 20 21 app = QApplication(shared.argv) 22 win = QMainWindow() 23 button = QPushButton("Quit", win) 24 button.clicked.connect(win.close) 25 win.show() 26 27 app.aboutToQuit.connect(lambda: shared.queue.put(None)) 28 app.exec_() 29 30 31def main(): 32 import sys 33 from types import SimpleNamespace 34 from multiprocessing import Process, Queue 35 36 shared = SimpleNamespace( 37 argv = sys.argv, 38 queue = Queue(), 39 ) 40 procTk = Process(target=tk_main, args=(shared,), daemon=True) 41 procQt = Process(target=qt_main, args=(shared,), daemon=True) 42 43 procTk.start() 44 procQt.start() 45 46 for item in iter(shared.queue.get, None): 47 queue.task_done() 48 49 50if __name__ == '__main__': 51 main() 52 53
tkinter と pyqt のウィンドウを同時に開くサンプル
このコードでは合計3つのプロセスを使いますが、最少は qt と tk の2つでも良いです。
終了時の処理を解りやすくするために3つにしました。
メインのプロセスではキューへのメッセージを待ち、
None が入れられるとプログラムを終了します。
qt <-> tk 間の連携には「プロセス間通信」を調べて見て下さい、
qt 側で読み取る Queue や tk 側で読み取る Queue を増やし、
Queue を通じてメッセージのやり取りをすることになります。
注意点: 終了時に tk/qt 側で何か処理を行う場合は、
daemon=False にして join メソッドでプロセスの終了を待ちます。
その場合、安全に各GUIのイベントループを終了する仕組みが必要になります。
qt/tk のイベントループを結合する方法
独自のイベントループを使う為、終了時のイベント処理は未対応。
デメリット:
- Qt の aboutToQuit シグナル等は期待通りに処理されない等、他への影響があります。
- 片方の遅延がもう片方に影響する。(tk のイベント処理が遅れると qt も遅くなる → 動作が重く)
別プロセスにした方が良いと思いますが、2つ以上のイベントループを使いたい場合、
このようなアプローチにすることも有ります。(例: asyncio + GUI 等)
python
1import sys 2import time 3from functools import partial 4from types import SimpleNamespace 5 6import tkinter as tk 7from PyQt5.QtCore import pyqtSignal 8from PyQt5.QtWidgets import QApplication, QMainWindow 9 10def my_quit(app, root, shared): 11 shared.stop_request = True 12 13def my_event_loop(app, root, shared): 14 while not shared.stop_request: 15 root.update() 16 app.processEvents() 17 time.sleep(0.1) 18 app.quit() 19 root.destroy() 20 21def main(): 22 app = QApplication(sys.argv) 23 root = tk.Tk() 24 shared = SimpleNamespace( 25 stop_request = False, 26 ) 27 cleanup = partial(my_quit, app, root, shared) 28 29 # tk widgets 30 root.protocol("WM_DELETE_WINDOW", cleanup) 31 button = tk.Button(root, text="OK") 32 button.pack() 33 34 # qt widgets 35 class MyMainWindow(QMainWindow): 36 closed = pyqtSignal() 37 def closeEvent(self, event): 38 self.closed.emit() 39 event.accept() 40 win = MyMainWindow() 41 win.closed.connect(cleanup) 42 win.show() 43 44 # XXX: app.aboutToQuit does not work 45 46 my_event_loop(app, root, shared) 47 48 49if __name__ == '__main__': 50 main()
投稿2020/12/10 06:31
編集2020/12/10 08:52総合スコア8729
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/12/10 06:55
2020/12/10 07:01
2020/12/10 07:20
2020/12/10 07:30
2020/12/10 07:56
2020/12/10 08:57 編集
2020/12/10 09:47