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.
Purchasing Power Parity
Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]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!
PyQt/PySide 1:1 Coaching with Martin Fitzpatrick — Get one on one help with your Python GUI projects. Working together with you I'll identify issues and suggest fixes, from bugs and usability to architecture and maintainability.
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.
Packaging Python Applications with PyInstaller by Martin Fitzpatrick — This step-by-step guide walks you through packaging your own Python applications from simple examples to complete installers and signed executables.