cookeh_a9 | 2020-12-05 00:13:58 UTC | #1
I've been working on a PyQT5 which has vertical tabs. However I am experiencing some odd behavior.
I have a class which inherits QApplication. When I create tabs within this class, behavior is as expected. However I want to add tabs via an event listener call. So within the class that inherits QApplication, I register a function which adds a tab.
When I add a tab via event listener call, the tab window goes outside the MainWindow. However if I just add it manually without event listener calls, the behavior is as expected.
Good and bad behaviors:
My guess is that I am using an old state of QApplication or MainWindow. I've spent a while trying to debug this and I do not see anyone who has ran into tabs appearing outside issue.
Code is below. I have commented in caps-lock the events. This is a rather sized application, so posting all the code isn't really feasible. I am hoping to get any ideas from anyone. Appreciate it.
Create GUI Applications with Python & Qt5 by Martin Fitzpatrick — (PyQt5 Edition) The hands-on guide to making apps with Python — Over 10,000 copies sold!
class MainWindow(QApplication):
def __init__(self, argv):
super().__init__(argv)
self.logic = None
self.logic_thread = None
self.basic_routine_cb = None
self.advanced_routine_cb = None
self.routine_frequency_drop_down = None
self.current_action_text = None
self.bot_running_time_value = None
self.total_rallies_joined_value = None
self.time_until_next_routine_value = None
self.routine_executed_at_value = None
self.bubble_time_checked_value = None
self.total_marches_drop_down = None
self.help_dialog = None
self.login = None
self.emulator_port_value = None
self.start_stop_button = None
self.total_preset_rotation_drop_down = None
self.consume_stamina_cb = None
self.w = None
self.win = MainApplicationWindow()
self.initialize_user_interface()
def initialize_user_interface(self):
QtWidgets.QApplication.setStyle(ProxyStyle())
self.setStyle('Fusion')
self.win.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.win.setGeometry(0, 0, 650, 525)
self.win.setFixedSize(650, 525)
self.win.setWindowTitle("Some Title")
self.w = TabWidget()
self.login = LoginForm(self)
tab1 = self.create_new_bot_tab()
self.w.addTab(tab1, QtGui.QIcon("./forum/images/RedSquare.png"), "1")
self.w.addTab(QWidget(), QtGui.QIcon("zoom.png"), "+")
self.w.currentChanged.connect(self.add_new_tab) #changed!
event_list.append(self.insert_new_bot_tab) # EVENT LISTENER ADDED HERE
self.win.setCentralWidget(self.w)
self.win.show()
self.login.show()
self.w.show()
sys.exit(self.exec_())
@pyqtSlot()
def add_new_tab(self):
try:
if Client.socket_connection.connected is False:
self.w.setCurrentIndex(self.w.currentIndex() - 1)
self.login.show()
return
if self.w.tabText(self.w.currentIndex()) != '+':
return
Client.attempt_add_tab() # THIS CALLS A FUNCTION WHICH EVENTUALLY CALLS THE REGISTERED EVENT
# IF I CALL self.insert_new_bot_tab() HERE RATHER THAN USING EVENT LISTENER TO CALL IT, BEHAVIOUR IS AS EXPECTED
except Exception as e:
print(str(e))
# THE REGISTERED EVENT HERE
def insert_new_bot_tab(self):
tab2 = self.create_new_bot_tab()
self.w.insertTab(self.w.currentIndex(), tab2, QtGui.QIcon("./forum/images/RedSquare.png"),
str(self.w.currentIndex() + 1))
self.w.blockSignals(True)
self.w.setCurrentIndex(self.w.currentIndex() - 1)
self.w.blockSignals(False)
def create_new_bot_tab(self):
wdg = CustomQWidget(self.win, self)
layout = QtWidgets.QGridLayout(wdg)
index = 0
if self.w.currentIndex() > -1:
index = self.w.currentIndex()
tabs = QTabWidget()
tab1 = StartMenuTab(self.login, self.w, index)
tab2 = ProfileTab()
tabs.resize(300, 200)
# Add tabs
tabs.addTab(tab1, "Start")
tabs.addTab(tab2, "Profile")
layout.addWidget(tabs)
return wdg
CustomQWidget class:
class CustomQWidget(QWidget):
def __init__(self, win, win_instance):
super().__init__(win)
self.win_instance = win_instance
cookeh_a9 | 2020-12-05 06:40:39 UTC | #2
I'm using a hackish work around for now. If anyone has any idea I would really appreciate feedback!
martin | 2020-12-08 12:08:16 UTC | #3
Hi @cookeh_a9 welcome to the forum!
First up, it's a bit strange to inherit from QApplication
, normally, you'd inherit from QMainWindow
for your main window. You then create an instance of QApplication
directly, create your window, and then start up the app event loop, e.g.
app = QApplication(sys.argv)
w = MainWindow()
app.exec_()
But I don't think that's the issue here. When you get windows popping out of the main window, it's usually an due to something going wrong with window parents -- any widget without a parent in Qt is a floating window. So if you create a QTabWidget
but don't set a parent (either explicitly, or by adding it to a layout) it will be floating. The same happens if you remove the parent from a widget by setting parent to None
.
Another way you can get caught out is by recreating a widget, e.g. if you have a tab widget as self.w
and then recreate the self.w = QTabWidget
again, the reference to the first tab widget is lost + it is destroyed. All widgets that had it as a parent (i.e. the tabs) are now parent-less and will free-float.
I'd start by checking the parent parameters you're passing to the various widgets when being created. Then double-check you're not recreating any widgets accidentally/unnecessarily.