Issue
I'm trying to turn a widget into a scrollable window. However, all I've accomplished is opening a QScrollarea that's completely independent from my central widget.
class Ui_MainWindow(object):
def mainscreen(self, MainWindow):
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.scrollArea = QtWidgets.QScrollArea()
self.scrollArea.setWidget(self.centralwidget)
MainWindow.setCentralWidget(self.centralwidget)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.mainscreen(MainWindow)
MainWindow.show()
app.exec_()
This just opens up my MainWindow on its own, only way I get an scrollarea open is if I do self.scrollarea.show . I cant figure out how QScrollArea works, how am I supposed to do it?
Solution
Simple explanation: the scroll area has no relation with the main window, and then it's not shown when the main window is.
Never, ever modify (or imitate) files generated by pyuic
You are making some confusion around the object structure, Qt parent/ownership and how a scroll area is set up.
This is also caused by the fact that you're clearly trying to mimic the structure and behavior of a file generated by pyuic, which should never be done. Those files are intended to be directly used as they are, without any modification, and imported in the main script of your program.
Their peculiar structure is intended only for that purpose, and the way they're built is not to be emulated, as creation of UI by code should only be done by subclassing a QWidget subclass (QMainWindow, QDialog, etc); trying to imitate what they do is not only unnecessary, but most times leads to confusion, bugs and unexpected behavior, exactly like in your case.
The only valid reason to open (and just read) a file generated by pyuic is to learn how widgets are created in the setupUi
, keeping in mind that the setupUi
argument (usually, MainWindow
for QMainWindows, Form
for QWidgets, Dialog
for QDialogs, unless the name of the top level widget is changed in the object inspector of designer) is the main widget on which the ui is built upon.
Manually editing those files should only be done if one really knows what she/he is doing. There are few, very rare cases for which this is considered necessary, and it's usually to workaround very specific known bugs in the uic module, that normally rise on very specific conditions and situations.
What is happening?
Then, when a QWidget instance is created with an existing widget as argument, the result is that the new widget becomes a child of the existing one.
Widget can be then reparented in various ways: by setting a widget for a scroll area using setWidget()
, or by setting the widget as a central widget to a QMainWindow.
What happens with your code is that you created a new QWidget that becomes a child of the QMainWindow with the following line:
self.centralwidget = QtWidgets.QWidget(MainWindow)
Then you create a scroll area (without any parent):
self.scrollArea = QtWidgets.QScrollArea()
Widgets that are not created with a parent are normally considered top level windows, unless they are added to a layout (or manually reparented using setParent()
, but that's another story), which causes the parent (the widget on which the layout is set) to take ownership of the new child widget. Otherwise, if you try to show the "parent-less" widget, it will be shown as a top level widget, meaning it will have its own window, and as any top level widget, they can only be shown by manually calling show()
or setVisible(True)
(and that's your case).
Then you try to set the centralwidget
of the scroll area, which will result in reparenting it:
self.scrollArea.setWidget(self.centralwidget)
Finally, you're setting that widget as the central widget, which will reparent it back again to the main window, with the result that the scroll area will not have a widget anymore (QObjects, from which QWidget inherits, can only have a single parent).
MainWindow.setCentralWidget(self.centralwidget)
The correct approach
The solution is to correctly create a QWidget (or QMainWindow in your case) subclass, set the scroll area as the central widget (if you want it as that) and create a new widget for its contents:
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.scrollArea = QtWidgets.QScrollArea()
self.setCentralWidget(self.scrollArea)
self.scrollArea.setWidgetResizable(True)
self.contents = QtWidgets.QWidget()
self.scrollArea.setWidget(self.contents)
# create a layout for the scroll area contents; using the target widget
# as argument of the layout constructor automatically sets the layout on
# the specified widget
layout = QtWidgets.QVBoxLayout(self.contents)
# the same as:
# layout = QtWidgets.QVBoxLayout()
# self.contents.setLayout(layout)
for row in range(20):
button = QtWidgets.QPushButton('button {}'.format(row + 1))
layout.addWidget(button)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.