How can I run an interface I made using PyQt5 and a Map program I made using Tkinter at the same time?

207 Views Asked by At

I am making an interface for an Unmanned Aerial Vehicle. I have a main interface that shows the data I get from the dronekit and the attitude indicator. I made this main interface using PyQt5, first I was going to add a map directly to this interface I made with PyQt5, but the map I used could not functionally work on the interface I made over PyQt5. So I decided to separate the main interface and the map. I made the map using "tkintermapwiever". When I run the two separately, it works smoothly and stably. But since we have a single tool and we will connect through the same server, both programs need to run simultaneously, my research has not yielded any results. I would be very grateful if you can help. Thank you..

I have tried Threading and Processing methods, but they work sequentially, not at the same time. So for example, my main interface opens first, and after I close my interface, my map application opens. It shouldn't be like this, both should open side by side at the same time. And there's this extra problem: in the code snippet below, as soon as I import root.tk, the map opens automatically.

block of code where I call two different files and try multiprocessing:

from multiprocessing import Process
from mainMap import root_tk
from mainarayüz import main


def arayuz() :
    p1 = Process(target= main())
    p2 = Process(root_tk.mainloop())
    
    p1.start()
    p2.start()
    p1.join()
    p2.join()

if __name__ == '__main__' :
    arayuz()
I managed to run both apps together, but after 1 second both apps froze and did not update themselves.

I will send the code:

from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from sarsgui_taslak import Ui_MainWindow
import sys
from PyQt5.QtCore import QUrl
from PyQt5.QtCore import QTimer
from geopy.geocoders import OpenCage
from PyQt5.QtGui import QFont,  QColor
from connecBaglanti import connect, connection_string, vehicle , VehicleMode, LocationLocal
from attitude_indicator import AttitudeIndicator
import datetime
import time
import math
import tkinter as tk
import tkintermapview
import time
import threading
import os
from PIL import Image, ImageTk
from connecBaglanti import connect, connection_string, vehicle, lat, lon
from multiprocessing import Process
 
# print("Simülatör başlatılıyor (SITL)")
# connection_string = "tcp:127.0.0.1:5762"
 
# print("Araç şurada bağlanıyor: %s" % (connection_string,))
# vehicle = connect(connection_string, wait_ready=False)
# # lat = vehicle.lsocation.global_relative_frame.lat
# lon = vehicle.location.global_relative_frame.lon
 
opencage_api_key = "52a.........................0"
 
class MainPage(QMainWindow):
    def __init__(self):
        super().__init__()
         
######MAIN INTERFACE STUFFFFFFFFFFFFFFFFFFFFFFFF
 
####################################MAP WITH TKINTER##############################################
def mapgui() :
    lat = vehicle.location.global_relative_frame.lat
    lon = vehicle.location.global_relative_frame.lon
    # create tkinter window
    root_tk = tk.Tk()
    root_tk.geometry(f"{1000}x{700}")
    root_tk.title("SarsGUI Map")
###MAP STUFFFF
    root_tk.mainloop()
 
 
     
def maingui():
    uygulama = QApplication([])
    pencere = MainPage()
    pencere.show()
    sys.exit(uygulama.exec_())
 
 
 
 
if __name__ == '__main__':
    pyqt_process = Process(target=maingui)
    tkinter_process = Process(target=mapgui)
 
    pyqt_process.start()
    tkinter_process.start()
 
    pyqt_process.join()
    tkinter_process.join()

I'm editing again. I only have one request, that the two programs run simultaneously at the same time. It doesn't matter if it is written in one program or not.

Here is the mainarayüz.py file:

from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from sarsgui_taslak import Ui_MainWindow
import sys
from PyQt5.QtCore import QUrl
from PyQt5.QtCore import QTimer
from geopy.geocoders import OpenCage
from PyQt5.QtGui import QFont,  QColor
from connecBaglanti import connect, connection_string, vehicle , VehicleMode, LocationLocal
from attitude_indicator import AttitudeIndicator
import datetime
import time
import math

opencage_api_key = "5............0"

class MainPage(QMainWindow):
   def __init__(self):
       super().__init__()
       ####stufstufffffff
   def modechange(self, nowmode) :
       ####stufstufffffff

   def rebootcom(self) :
       ####stufstufffffff
   def armcom(self) :
       ####stufstufffffff
   def disarmcom(self) :
       ####stufstufffffff
   def updatearm(self) :
       ####stufstufffffff

   
   def go_right(self) :
       ####stufstufffffff
   def go_left(self) :
       ####stufstufffffff

   def go_forward(self) :
       ####stufstufffffff
   def go_backward(self) :
       ####stufstufffffff
       time.sleep(0.5)
       ####stufstufffffff




   def update_location_and_marker(self):
       ####stufstufffffff
       
   def updatePitch(self, pitch):
       ####stufstufffffff
   def updateRoll(self, roll):
       ####stufstufffffff
   def update(self):
       ####stufstufffffff
   
def main():
   uygulama = QApplication([])
   pencere = MainPage()
   pencere.show()
   sys.exit(uygulama.exec_())

if __name__ == "__main__":
   main()

This is the mainMap.py file:

import tkinter
import tkintermapview
import time
import threading
import os
from PIL import Image, ImageTk
from connecBaglanti import connect, connection_string, vehicle, lat, lon
lat = vehicle.location.global_relative_frame.lat
lon = vehicle.location.global_relative_frame.lon
root_tk = tkinter.Tk()
root_tk.geometry(f"{1000}x{700}")
root_tk.title("SarsGUI Map")
#############stufstufffffff

def clear_previous_marker():
    #############stufstufffffff

# Konum güncelleme iş parçacığını başlatın
def update_position():
    #############stufstufffffff
    while True:
        #############stufstufffffff

#############stufstufffffff

root_tk.mainloop()

This is the mapwithGUI.py file that tries to make the interface.py file and the mainMap.py file open at the same time:

import subprocess
import time
import os

def run_two():
    
    p1 = subprocess.Popen(["python", "mainarayüz.py"])
    p2 = subprocess.Popen(["python", "mainMap.py"])

    while True:
        if p1.poll() is not None:
            p2.terminate()
            break
        elif p2.poll() is not None:
            p1.terminate()
            break
        time.sleep(1.0)

    p1.wait(1.0)
    p2.wait(1.0)
    print("Tamamlandı")

if __name__ == "__main__":
    run_two()

In the mapwithGUI.py file, I am trying to make both of them work simultaneously, but at first the map comes up (mainMap.py), after I close it, the interface (maininterface.py) comes up. If I do not close the map, the interface does not come.

The Last Edit:

The dronekit library that I use in both mainMap.py and maininterface.py, where I connect the map and interface to the uav (maybe this is the problem) :

from dronekit import Command, connect, VehicleMode, LocationGlobalRelative, LocationLocal,__init__

# print("Simülatör başlatılıyor (SITL)")
connection_string = "tcp:127.0.0.1:5762"

print("Araç şurada bağlanıyor: %s" % (connection_string,))
vehicle = connect(connection_string, wait_ready=False)

https://drive.google.com/file/d/1OC-JwTG01P_whg_fw_FkKstUIEjtlm7F/view

THE LAST AND LAST EDIT:

I did it. I put two separate programs under one program like two main functions (as I mentioned above at the beginning). The process method didn't work again, but the threading method did. I think this is related to using the same memory space.

2

There are 2 best solutions below

1
John Bollinger On

It should be possible to run the two GUIs in separate programs. I'm not sure what specifically you tried with multiprocessing, but that's indeed one way it should be possible to get that running.

There is no good way to make it work in a single program. Each toolkit needs to have control of the the queue of GUI events in order to respond appropriately. It might be possible in principle to bridge those with some kind of mapping, but I'm not aware of any existing mechanism for doing that, and if it's possible at all then it is surely much more than you will want to take on personally.

19
Paul Cornelius On

I am a bit confused by your question, since you keep insisting that you have no intention to combine the two GUIs into a single program yet in your code you are trying to do exactly that. You didn't respond to my comment where I asked why you can't simply run the two programs at the same time, using standard operating system methods. Based on the code you provided, there is no interaction at all between your two programs, so there is no particular reason why they have to be started from the same Python script. However, putting all that aside and apologizing again for my possible misunderstanding, here is an idea for you:

Step 1 is to separate the PyQt program from the TkInter program. Put their entry points into two different files, so that they are literally two completely separate programs. They know nothing about each other.

Step 2 is to launch both programs from the same Python script, using methods in the subprocess module.

Here is an example of how you might do this. In my case both programs are tkinter programs, but it doesn't matter. There are three files involved. First here is a4a.py:

import tkinter as tk
import random

def test_gui():
    root_tk = tk.Tk()
    root_tk.geometry(f"{1000}x{700}")
    root_tk.title(f"Test program {random.random()}")
    root_tk.mainloop()

if __name__ == "__main__":
    test_gui()

It looks a bit like your mapgui() program. Here is a4b.py:

import tkinter as tk
import random

def test_gui():
    root_tk = tk.Tk()
    root_tk.geometry(f"{1000}x{700}")
    root_tk.title(f"Test program {random.random()}")
    root_tk.mainloop()

if __name__ == "__main__":
    test_gui()

It's exactly the same code, because it's just for illustration. I've put a random number in the window title so I can tell them apart. In your case, one would be the tkinter program and the other would be the PyQt5 program.

Here is the third file, a4.py:

import subprocess
import time

def run_two():
    p1 = subprocess.Popen(["python3.11", "a4a.py"])
    p2 = subprocess.Popen(["python3.11", "a4b.py"])
    while True:
        if p1.poll() is not None:
            p2.terminate()
            break
        elif p2.poll() is not None:
            p1.terminate()
            break
        time.sleep(1.0)
    p1.wait(1.0)
    p2.wait(1.0)
    print("Finished")

if __name__ == "__main__":
    run_two()

This script launches the two other programs, and checks once per second to see if either if them has been terminated. If it is, the script terminates the other one and exits.

I hope this is what you are looking for.