Unable to add a widget to a QScrollArea object dynamically
-
Hi, guys! I met two problems when I want to add a widget to a
QScrollArea
object dynamically. When I comment that line, the new widget I want to add could not be displayed on the screen. Moreover, I found that I could not scroll that area on the screen.Thank you very much for any help!
from PyQt5.QtWidgets import * class MyList(QScrollArea): def __init__(self): super().__init__() self._widget = QWidget() self._layout = QVBoxLayout() # If I comment this line, MyButton._add function will not work, and the screen will not display new widget. self._layout.addWidget(QPushButton('test')) # set layout and widget self._widget.setLayout(self._layout) self.setWidget(self._widget) # display settings self.setMinimumSize(1024, 540) class MyButton(QPushButton): def __init__(self, text, _list): super().__init__(text=text) self._list = _list self.clicked.connect(self._add) def _add(self): self._list._layout.addWidget(QPushButton('test')) class MainWindow(QWidget): def __init__(self): super().__init__() self._layout = QVBoxLayout() self._my_list = MyList() self._my_button = MyButton(text='Add', _list=self._my_list) self._layout.addWidget(self._my_list) self._layout.addWidget(self._my_button) # set layout self.setLayout(self._layout) # display settings self.setWindowTitle('My Demo') def main(): app = QApplication([]) main_window = MainWindow() main_window.show() app.exec_() if __name__ == "__main__": main()
-
I figure out the reason with the help of @T.sagiv.
The solution is that I have to adjust the scrollarea. Just replaceself.setMinimumSize(1024, 540)
withself.setWidgetResizable(True)
. -
Hi, guys! I met two problems when I want to add a widget to a
QScrollArea
object dynamically. When I comment that line, the new widget I want to add could not be displayed on the screen. Moreover, I found that I could not scroll that area on the screen.Thank you very much for any help!
from PyQt5.QtWidgets import * class MyList(QScrollArea): def __init__(self): super().__init__() self._widget = QWidget() self._layout = QVBoxLayout() # If I comment this line, MyButton._add function will not work, and the screen will not display new widget. self._layout.addWidget(QPushButton('test')) # set layout and widget self._widget.setLayout(self._layout) self.setWidget(self._widget) # display settings self.setMinimumSize(1024, 540) class MyButton(QPushButton): def __init__(self, text, _list): super().__init__(text=text) self._list = _list self.clicked.connect(self._add) def _add(self): self._list._layout.addWidget(QPushButton('test')) class MainWindow(QWidget): def __init__(self): super().__init__() self._layout = QVBoxLayout() self._my_list = MyList() self._my_button = MyButton(text='Add', _list=self._my_list) self._layout.addWidget(self._my_list) self._layout.addWidget(self._my_button) # set layout self.setLayout(self._layout) # display settings self.setWindowTitle('My Demo') def main(): app = QApplication([]) main_window = MainWindow() main_window.show() app.exec_() if __name__ == "__main__": main()
@sunshk1227 said in Unable to add a widget to a QScrollArea object dynamically:
When I comment that line, the new widget I want to add could not be displayed on the screen
Of course not. But you did not explain what happens if you do NOT comment it out. So, what is actually the problem?
-
@sunshk1227 said in Unable to add a widget to a QScrollArea object dynamically:
When I comment that line, the new widget I want to add could not be displayed on the screen
Of course not. But you did not explain what happens if you do NOT comment it out. So, what is actually the problem?
@jsulm Hi, sorry I was not clear. When I comment that out, nothing happens if I click the "Add" button. But I print the number of the widget in
main_window._my_list._layout.count()
, the number increases correctly. -
@jsulm Hi, sorry I was not clear. When I comment that out, nothing happens if I click the "Add" button. But I print the number of the widget in
main_window._my_list._layout.count()
, the number increases correctly.@sunshk1227 Try to call show() on new buttons:
def _add(self): b = QPushButton('test') self._list._layout.addWidget(b) b.show()
-
@sunshk1227 Try to call show() on new buttons:
def _add(self): b = QPushButton('test') self._list._layout.addWidget(b) b.show()
@jsulm Hi, thank you for your help! But it seems that it does not work.
(By the way, if I do NOT comment it out, a new button will be displayed on the screen when I click the "Add" button...)
-
@jsulm Hi, thank you for your help! But it seems that it does not work.
(By the way, if I do NOT comment it out, a new button will be displayed on the screen when I click the "Add" button...)
@sunshk1227 Strange.
Not a solution for the problem, but an improvement idea: instead of exposing internals of the MyList class (_layout) to the outside world you should make it private and add a method to add new widgets (like buttons).class MyList(QScrollArea): ... def addWidget(self, widget): self.__layoutaddWidget(widget)
This way MyButton does not have to know where to add new buttons to the list:
def _add(self): self._list.addWidget(QPushButton('test'))
You could improve your design even more if you remove self._list from MyButton completely and instead emit a signal in MyButton and connect it to a slot in MyList. This way MyButton and MyList do not have to know anything about each other.
-
@sunshk1227 Strange.
Not a solution for the problem, but an improvement idea: instead of exposing internals of the MyList class (_layout) to the outside world you should make it private and add a method to add new widgets (like buttons).class MyList(QScrollArea): ... def addWidget(self, widget): self.__layoutaddWidget(widget)
This way MyButton does not have to know where to add new buttons to the list:
def _add(self): self._list.addWidget(QPushButton('test'))
You could improve your design even more if you remove self._list from MyButton completely and instead emit a signal in MyButton and connect it to a slot in MyList. This way MyButton and MyList do not have to know anything about each other.
@jsulm Thank you very much for your suggestions! Got it. But I still have a question... should I further improve my design like this? (In this case, could you please tell me how to connect a function with an additional argument, where I marked by '?' in my code?)
Thank you again for your advice!class MyList(QScrollArea): ... def _addWidget(self, widget): self._layout.addWidget(widget) class MyButton(QPushButton): def __init__(self, text): super().__init__(text=text) class MainWindow(QWidget): def __init__(self): ... self._my_list = MyList() self._my_button = MyButton(text='Add') self._my_button.clicked.connect(self._my_list._addWidget(?)) ... ... ...
-
@jsulm Thank you very much for your suggestions! Got it. But I still have a question... should I further improve my design like this? (In this case, could you please tell me how to connect a function with an additional argument, where I marked by '?' in my code?)
Thank you again for your advice!class MyList(QScrollArea): ... def _addWidget(self, widget): self._layout.addWidget(widget) class MyButton(QPushButton): def __init__(self, text): super().__init__(text=text) class MainWindow(QWidget): def __init__(self): ... self._my_list = MyList() self._my_button = MyButton(text='Add') self._my_button.clicked.connect(self._my_list._addWidget(?)) ... ... ...
@sunshk1227 said in Unable to add a widget to a QScrollArea object dynamically:
self._my_button.clicked.connect(self._my_list._addWidget(?))
This is wrong, should be:
self._my_button.clicked.connect(self._my_list._addWidget)
In this line you only connect the signal to the slot, you do not call the slot. Slot will be called as soon as signal is emitted.
class MyButton(QPushButton): newWidget = pyqtSignal() def __init__(self, text): super().__init__(text=text) self.clicked.connect(self._add) def _add(self): newWidget.emit(QPushButton('test')) self._my_button.newWidget.connect(self._my_list._addWidget)
Not sure this 100% correct as I don't use PyQt/PiSide :-)
-
I figure out the reason with the help of @T.sagiv.
The solution is that I have to adjust the scrollarea. Just replaceself.setMinimumSize(1024, 540)
withself.setWidgetResizable(True)
. -
@sunshk1227 said in Unable to add a widget to a QScrollArea object dynamically:
self._my_button.clicked.connect(self._my_list._addWidget(?))
This is wrong, should be:
self._my_button.clicked.connect(self._my_list._addWidget)
In this line you only connect the signal to the slot, you do not call the slot. Slot will be called as soon as signal is emitted.
class MyButton(QPushButton): newWidget = pyqtSignal() def __init__(self, text): super().__init__(text=text) self.clicked.connect(self._add) def _add(self): newWidget.emit(QPushButton('test')) self._my_button.newWidget.connect(self._my_list._addWidget)
Not sure this 100% correct as I don't use PyQt/PiSide :-)
-
@jsulm said in Unable to add a widget to a QScrollArea object dynamically:
Not sure this 100% correct as I don't use PyQt/PiSide :-)
newWidget.emit(QPushButton('test'))
Whazzis? :)
-
@jsulm
Yeah but I was suprised at your parameter! Yours isemit newWidget(new QPushButton("test"))
, is that what you intended? I didn't really read what OP wanted :-; So you want to emit a signal which accepts an unplacednew
widget, presumably the slot does something with it? Interesting! -
@jsulm
Yeah but I was suprised at your parameter! Yours isemit newWidget(new QPushButton("test"))
, is that what you intended? I didn't really read what OP wanted :-; So you want to emit a signal which accepts an unplacednew
widget, presumably the slot does something with it? Interesting!