I have QTabWidget, and layout with some widgets and sub layouts that I want to show in this QTabWidget tabs. what I want to do is to add this layout to the first tab (as default), and if the user moves to the next tab, I want to show the exact same layout, and to add some widgets near it.
this is the layout that I am talking about:
self.right_tab_layout = QVBoxLayout()
self.right_tab_widget = QWidget()
self.right_tab_title_label = QLabel("Select full files path:")
self.simoderev_layout = QHBoxLayout()
self.simoderev_widget = QWidget()
self.simoderev_checkbox = QCheckBox("use simoderev as base: ")
self.simoderev_combobox = QComboBox()
self.paths_label = QLabel("paths:")
self.right_tab_widget.setLayout(self.right_tab_layout)
self.simoderev_widget.setLayout(self.simoderev_layout)
self.simoderev_widget.setMaximumWidth(250)
self.simoderev_layout.addWidget(self.simoderev_checkbox)
self.simoderev_layout.addWidget(self.simoderev_combobox)
self.simoderev_layout.setContentsMargins(0,0,0,0)
self.right_tab_layout.addWidget(self.right_tab_title_label)
self.right_tab_layout.addWidget(self.simoderev_widget)
self.right_tab_layout.addWidget(self.paths_label)
is there any way to do this ?
If you just want the widgets in the tabs to look the same, you should create a custom Widget class and put an instance of that class in each tab.
Your custom widget could look like:
class CustomWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(CustomWidget, self).__init__(parent)
layout = QtGui.QVBoxLayout(self)
self.title_label = QtGui.QLabel("Select full files path:")
self.simoderev_widget = QtGui.QWidget()
simoderev_layout = QtGui.QHBoxLayout(self.simoderev_widget)
self.simoderev_checkbox = QtGui.QCheckBox("use simoderev as base: ")
self.simoderev_combobox = QtGui.QComboBox()
self.simoderev_widget.setMaximumWidth(250)
simoderev_layout.addWidget(self.simoderev_checkbox)
simoderev_layout.addWidget(self.simoderev_combobox)
simoderev_layout.setContentsMargins(0,0,0,0)
self.paths_label = QtGui.QLabel("paths:")
layout.addWidget(self.title_label)
layout.addWidget(self.simoderev_widget)
layout.addWidget(self.paths_label)
If you want them to be the same, here's a hacky solution. You should connect the currentChanged signal of your tabwidget to a slot that will move your custom widget from one tab to the other.
class MyTabWidget(QtGui.QTabWidget):
def __init__(self, parent = None):
super(MyTabWidget, self).__init__(parent)
self.subwidget = CustomWidget(self)
self.left_tab_widget = QtGui.QWidget()
self.leftLayout = QtGui.QVBoxLayout(self.left_tab_widget)
self.leftLayout.addWidget(self.subwidget)
self.right_tab_widget = QtGui.QWidget(self)
self.rightLayout = QtGui.QVBoxLayout(self.right_tab_widget)
label = QtGui.QLabel("Some additional data", self.right_tab_widget)
self.rightLayout.addWidget(label)
self.addTab(self.left_tab_widget, "Left Tab")
self.addTab(self.right_tab_widget, "Right Tab")
self.currentChanged.connect(self.onCurrentChanged)
def onCurrentChanged(self, index):
if index == 0:
self.leftLayout.addWidget(self.subwidget)
else:
self.rightLayout.addWidget(self.subwidget)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
widget = MyTabWidget()
widget.show()
app.exec_()
Related
I am implement my-self label, but some widget is disappear.
My code is:
from PyQt5.QtWidgets import *
import sys
class TypeManagerLabel(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
btnLayout = QHBoxLayout()
self.__nameLineEdit = QLineEdit()
self.__opBtn = QPushButton('Add/Remove')
self.__colorBtn = QPushButton('Color')
btnLayout.addWidget(self.__nameLineEdit)
btnLayout.addWidget(self.__opBtn)
layout.addLayout(btnLayout)
class MyWin(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
lab1 = TypeManagerLabel()
layout.addWidget(lab1)
# layout.addStretch()
lab2 = QPushButton('test')
layout.addWidget(lab2)
app = QApplication(sys.argv)
dialog = MyWin()
dialog.show()
app.exec_()
Currently, the label is OK, and the result should be:
Now, I want the QLineEdit should be located on the top of the label, thus I add a stretch. And the code is:
class MyWin(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
lab1 = TypeManagerLabel()
layout.addWidget(lab1)
layout.addStretch() ###################### add the stretch
lab2 = QPushButton('test')
layout.addWidget(lab2)
And the result is:
In the above figure, the QLineEdit is disappeared.
#
My environment is:
win 10
python 3.7.8
pyqt5 5.14.0
--------------------------------update ----------------------------------
Thank for the suggestion from musicamante and Heike, subclass QWidget instead of QLabel. But the new bug is reported after I add some new widget. The code is:
from PyQt5.QtWidgets import *
import sys
class TypeManagerLabel(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
btnLayout = QHBoxLayout()
self.__nameLineEdit = QLineEdit()
self.__opBtn = QPushButton('Add')
btnLayout.addWidget(self.__nameLineEdit)
btnLayout.addWidget(self.__opBtn)
layout.addLayout(btnLayout)
infoLabel = QLabel()
layout.addWidget(infoLabel)
self.__infoLayout = QVBoxLayout()
infoLabel.setLayout(self.__infoLayout)
self.__opBtn.clicked.connect(self.addRemoveSlot)
def addRemoveSlot(self, checked=False):
name = self.__nameLineEdit.text()
layout = QHBoxLayout()
checkBox = QCheckBox()
lineEdit = QLineEdit(name)
layout.addWidget(checkBox)
layout.addWidget(lineEdit)
self.__infoLayout.addLayout(layout)
class MyWin(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
lab1 = TypeManagerLabel()
layout.addWidget(lab1)
# layout.addStretch()
lab2 = QPushButton('test')
layout.addWidget(lab2)
app = QApplication(sys.argv)
dialog = MyWin()
dialog.show()
app.exec_()
When I input a string in the QLineEdit, and click the "Add" button, the result is:
The above figure is what I expected.
But if I add stretch with the code:
class MyWin(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
lab1 = TypeManagerLabel()
layout.addWidget(lab1)
layout.addStretch() ###################### add the stretch
lab2 = QPushButton('test')
layout.addWidget(lab2)
Then, if I input a string in the QLineEdit and click the 'Add' button, the expected widget would not appear.
QLabel is a very special type of widget. While it seems very simple, it is not: it has its own behavior when dealing with sizes, and that's in order to accomodate all requirements a widget that is primarily based on (possibly) variable text size, not only horizontally, but vertically also.
That said, one should never try to add layouts and child widgets to classes that are not intended to be used as container, most importantly it should not be done on widgets with peculiar behavior like QLabel.
Using such a widget to contain other widgets is not only a very bad idea, but also completely useless, as you're not actually using the real features a QLabel provides (showing text or images).
To add children and layouts, just use a nested layout, a plain QWidget class, or any other container widgets like QGroupBox or QFrame.
Even after the comments, you're still trying to add widgets to a QLabel. Remove that label, and just add the layout to the main one.
class TypeManagerLabel(QWidget):
def __init__(self):
super().__init__()
# ...
layout.addLayout(btnLayout)
self.__infoLayout = QVBoxLayout()
layout.addLayout(self.__infoLayout)
self.__opBtn.clicked.connect(self.addRemoveSlot)
# ...
I'm adding a toolbar to a widget, and dynamically hiding actions (they are also used in context menus). I'm encountering some problem with alignment/size. In the image below, Test 1 is "correct", and I want the other two to have only the "C" button, right-aligned (as in Test 3, but without the extra left space).
The code shows my attempt. Test 2 simply uses .setVisible(False) on the action A and B, while Test 3 does the same and adds a couple of empty QLabel on the left (if I add only one), the C does not end up right-aligned. It looks like QToolBar wants a minimum of 3 buttons or something.
Any idea how to fix this?
#!/usr/bin/env python
from PyQt4.QtGui import *
import sys
class MainWindow(QMainWindow):
def __init__(self):
super(QMainWindow, self).__init__()
stylesheet = 'QToolButton{padding: 0; margin: 0} QToolBar{border: 1px solid black}'
layout = QVBoxLayout()
a = QAction('A', self)
b = QAction('B', self)
c = QAction('C', self)
toolbar = QToolBar()
toolbar.addAction(a)
toolbar.addAction(b)
toolbar.addAction(c)
toolbar.setStyleSheet(stylesheet)
hbox = QHBoxLayout()
hbox.addWidget(QLabel('Test 1'))
hbox.addStretch(1)
hbox.addWidget(toolbar)
group = QGroupBox()
group.setLayout(hbox)
layout.addWidget(group)
a = QAction('A', self)
b = QAction('B', self)
c = QAction('C', self)
toolbar = QToolBar()
toolbar.addAction(a)
toolbar.addAction(b)
toolbar.addAction(c)
a.setVisible(False)
b.setVisible(False)
toolbar.setStyleSheet(stylesheet)
hbox = QHBoxLayout()
hbox.addWidget(QLabel('Test 2'))
hbox.addStretch(1)
hbox.addWidget(toolbar)
group = QGroupBox()
group.setLayout(hbox)
layout.addWidget(group)
a = QAction('A', self)
b = QAction('B', self)
c = QAction('C', self)
toolbar = QToolBar()
toolbar.addWidget(QLabel(''))
toolbar.addWidget(QLabel(''))
toolbar.addAction(a)
toolbar.addAction(b)
toolbar.addAction(c)
a.setVisible(False)
b.setVisible(False)
toolbar.setStyleSheet(stylesheet)
hbox = QHBoxLayout()
hbox.addWidget(QLabel('Test 3'))
hbox.addStretch(1)
hbox.addWidget(toolbar)
group = QGroupBox()
group.setLayout(hbox)
layout.addWidget(group)
layout.addStretch(1)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.show()
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())
To dynamically hide actions in a QToolbar, you cannot use setVisible(False) on the action since it will only "hide" the action from view but the button is inherently still there which is why you have the extra white space. Even though the action is hidden, there is still padding from a hidden object which gives you the undesired empty space. Similarly, when you add empty QLabels, this "hidden" widget also leaves white space since the physical area of the widget is still there.
Considering this, a solution is to remove the action from the QToolbar using removeAction(). This way, the actual object will be removed from the layout so there is no white space. Here's an example that shows how to add and remove actions in a QToolbar using handlers. You can check what objects are in the Qtoolbar with .actions() and depending on what action you want to remove, you can simply pass this to removeAction(). I'll leave it up to you to implement error handling when there are no more actions to add or no more actions to remove.
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class MainWindow(QMainWindow):
def __init__(self):
super(QMainWindow, self).__init__()
self.stylesheet = 'QToolButton{padding: 0; margin: 0} QToolBar{border: 1px solid black}'
self.main_layout = QGridLayout()
self.layout = QVBoxLayout()
self.a = QAction('A', self)
self.b = QAction('B', self)
self.c = QAction('C', self)
self.action_table = {1: self.a,
2: self.b,
3: self.c
}
self.test1_toolbar = QToolBar()
self.test1_toolbar.addAction(self.a)
self.test1_toolbar.addAction(self.b)
self.test1_toolbar.addAction(self.c)
self.test1_toolbar.setStyleSheet(self.stylesheet)
self.test1_hbox = QHBoxLayout()
self.test1_hbox.addWidget(QLabel('Test 1'))
self.test1_hbox.addStretch(1)
self.test1_hbox.addWidget(self.test1_toolbar)
self.test1_group = QGroupBox()
self.test1_group.setLayout(self.test1_hbox)
self.layout.addWidget(self.test1_group)
self.test2_toolbar = QToolBar()
self.test2_toolbar.addAction(self.a)
self.test2_toolbar.addAction(self.b)
self.test2_toolbar.addAction(self.c)
self.test2_toolbar.setStyleSheet(self.stylesheet)
self.test2_add_button = QPushButton('Add')
self.test2_add_button.clicked.connect(self.test2_add_action)
self.test2_remove_button = QPushButton('Remove')
self.test2_remove_button.clicked.connect(self.test2_remove_action)
self.test2_hbox = QHBoxLayout()
self.test2_hbox.addWidget(QLabel('Test 2'))
self.test2_hbox.addStretch(1)
self.test2_hbox.addWidget(self.test2_toolbar)
self.test2_group = QGroupBox()
self.test2_group.setLayout(self.test2_hbox)
self.layout.addWidget(self.test2_group)
self.test3_toolbar = QToolBar()
self.test3_toolbar.addAction(self.a)
self.test3_toolbar.addAction(self.b)
self.test3_toolbar.addAction(self.c)
self.test3_toolbar.setStyleSheet(self.stylesheet)
self.test3_hbox = QHBoxLayout()
self.test3_hbox.addWidget(QLabel('Test 3'))
self.test3_hbox.addStretch(1)
self.test3_hbox.addWidget(self.test3_toolbar)
self.test3_group = QGroupBox()
self.test3_group.setLayout(self.test3_hbox)
self.layout.addWidget(self.test3_group)
self.layout.addStretch(1)
self.widget = QWidget()
self.main_layout.addLayout(self.layout,0,0,1,1)
self.main_layout.addWidget(self.test2_add_button,0,1,1,1)
self.main_layout.addWidget(self.test2_remove_button,0,2,1,1)
self.widget.setLayout(self.main_layout)
self.setCentralWidget(self.widget)
self.show()
def test2_add_action(self):
objects = len(self.test2_toolbar.actions())
self.test2_toolbar.addAction(self.action_table[objects + 1])
def test2_remove_action(self):
objects = len(self.test2_toolbar.actions())
self.test2_toolbar.removeAction(self.action_table[objects])
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())
I'm trying to make a gui that allows the addition/removal of multiple QtWidgets. The user selects a file and has the option off adding a comment in the lineedit next to it. A quick search on this site has so far given me the following code which allows me to add rows widgets.
import os
import sys
from PyQt5 import QtGui, QtCore, QtWidgets
class Additional(QtWidgets.QMainWindow):
def __init__(self):
super(Additional, self).__init__()
self.addButton = QtWidgets.QPushButton(' + ')
self.delButton = QtWidgets.QPushButton(' - ')
self.acceptButton = QtWidgets.QPushButton('Accept')
self.cancelButton = QtWidgets.QPushButton('Cancel')
self.addButton.clicked.connect(self.addWidget)
self.delButton.clicked.connect(self.delWidget)
self.acceptButton.clicked.connect(self.acceptValues)
self.cancelButton.clicked.connect(self.cancel)
self.scrollLayout = QtWidgets.QFormLayout()
self.scrollWidget = QtWidgets.QWidget()
self.scrollWidget.setLayout(self.scrollLayout)
self.scrollArea = QtWidgets.QScrollArea()
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setWidget(self.scrollWidget)
self.button_layout = QtWidgets.QVBoxLayout()
self.mainLayout = QtWidgets.QHBoxLayout()
self.button_layout.addWidget(self.addButton)
self.button_layout.addWidget(self.delButton)
self.button_layout.addWidget(self.acceptButton)
self.button_layout.addWidget(self.cancelButton)
self.mainLayout.addLayout(self.button_layout)
self.mainLayout.addWidget(self.scrollArea)
self.centralWidget = QtWidgets.QWidget()
self.centralWidget.setLayout(self.mainLayout)
self.setCentralWidget(self.centralWidget)
self.resize(800, 200)
self.setFixedSize(self.size())
self.show()
def addWidget(self):
self.scrollLayout.addRow(AddRow())
def delWidget(self):
# Would this call another class to remove the row? If so, how?
pass
def acceptValues(self):
# Would I count the widgets in the 'scroll' area and get the data from that?
pass
def cancel(self):
QtCore.QCoreApplication.instance().quit()
# BTW, is this the right way to close the window/instance?
class AddRow(QtWidgets.QWidget):
def __init__( self, parent=None):
super(AddRow, self).__init__(parent)
self.button = QtWidgets.QPushButton('Select file')
self.label = QtWidgets.QLabel('Selection will go here')
self.lineedit = QtWidgets.QLineEdit()
self.lineedit.setPlaceholderText("Rename (optional)...")
# Would I add the button callback here?
layout = QtWidgets.QHBoxLayout()
layout.addWidget(self.button)
layout.addWidget(self.label)
layout.addWidget(self.lineedit)
self.setLayout(layout)
app = QtWidgets.QApplication(sys.argv)
myApp = Additional()
app.exec_()
I'm trying to figure out:
How to delete the last row that's been added.
How to assign the action to the button (this be done in the 'AddRow'
class likeself.buttton.clicked.callback(self.selectfile)
How to collect the data from the rows (ie, after 'accept' has been
clicked)
Any ideas would be welcome!
Before pointing to the solution, I'm just going to change the name of the AddRow class to RowWidget because a class should not indicate action.
class RowWidget(QtWidgets.QWidget):
def __init__( self, parent=None):
super(RowWidget, self).__init__(parent)
...
How to delete the last row that's been added ?
Since you are using QFormLayout and assuming that you are using a version PyQt5>=5.8 you can use the removeRow() method:
#QtCore.pyqtSlot()
def delWidget(self):
if self.scrollLayout.rowCount() > 0:
self.scrollLayout.removeRow(self.scrollLayout.rowCount()-1)
How to assign the action to the button (this be done in the 'AddRow' class likeself.buttton.clicked.callback(self.selectfile)?
Each part of your application must be independent so the slot that you select the file must be part only of RowWidget, and RowWidget must have a method that returns that value:
class RowWidget(QtWidgets.QWidget):
def __init__( self, parent=None):
super(RowWidget, self).__init__(parent)
self.button = QtWidgets.QPushButton('Select file')
self.label = QtWidgets.QLabel('Selection will go here')
self.lineedit = QtWidgets.QLineEdit()
self.lineedit.setPlaceholderText("Rename (optional)...")
self.button.clicked.connect(self.on_select_file)
layout = QtWidgets.QHBoxLayout(self)
layout.addWidget(self.button)
layout.addWidget(self.label)
layout.addWidget(self.lineedit)
#QtCore.pyqtSlot()
def on_select_file(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open File")
if filename:
self.lineedit.setText(filename)
def get_filename(self):
return self.lineedit.text()
How to collect the data from the rows (ie, after 'accept' has been clicked)?
The widgets attached to a layout are children of the widget where the layout has been added, that widget can be obtained through parentWidget(), having that parent we can obtain their children through findChildren():
#QtCore.pyqtSlot()
def acceptValues(self):
l_values = []
for w in self.scrollLayout.parentWidget().findChildren(RowWidget):
l_values.append(w.get_filename())
print(l_values)
The previous method may fail if the parentWidget() has other children that belong to RowWidget.
Another option, and that does not fail is to iterate through the QLayoutItems:
#QtCore.pyqtSlot()
def acceptValues(self):
l_values = []
for i in range(self.scrollLayout.rowCount()):
layout_item = self.scrollLayout.itemAt(i)
if isinstance(layout_item.widget(), RowWidget):
l_values.append(layout_item.widget().get_filename())
print(l_values)
I am trying to create a dialog with three tabs using PyQt. However, I am annoyed because although the dialog is displayed, the embedded widgets are not displayed!. I suppose this is a very simple problem with a correspondingly very simple solution, but I am struck! Can anyone give a hint? Thanks in advance!
Here is my code so far:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class TabbedDialog(QDialog):
def __init__(self, parent = None):
super(TabbedDialog, self).__init__(parent)
self.tabWidget = QTabWidget()
self.tabWidget.tab1 = QWidget()
self.tabWidget.tab2 = QWidget()
self.tabWidget.tab3 = QWidget()
self.tabWidget.addTab(self.tabWidget.tab1,"Tab 1")
self.tabWidget.addTab(self.tabWidget.tab2,"Tab 2")
self.tabWidget.addTab(self.tabWidget.tab3,"Tab 3")
self.tab1UI()
self.tab2UI()
self.tab3UI()
self.setWindowTitle("tab demo")
def tab1UI(self):
layout = QFormLayout()
layout.addRow("Name",QLineEdit())
layout.addRow("Address",QLineEdit())
self.tabWidget.setTabText(0,"Contact Details")
self.tabWidget.tab1.setLayout(layout)
def tab2UI(self):
layout = QFormLayout()
sex = QHBoxLayout()
sex.addWidget(QRadioButton("Male"))
sex.addWidget(QRadioButton("Female"))
layout.addRow(QLabel("Sex"),sex)
layout.addRow("Date of Birth",QLineEdit())
self.tabWidget.setTabText(1,"Personal Details")
self.tabWidget.tab2.setLayout(layout)
def tab3UI(self):
layout = QHBoxLayout()
layout.addWidget(QLabel("subjects"))
layout.addWidget(QCheckBox("Physics"))
layout.addWidget(QCheckBox("Maths"))
self.tabWidget.setTabText(2,"Education Details")
self.tabWidget.tab3.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
form = TabbedDialog()
retval = form.exec_()
here is my solution to the problem
On the init method, I declared a layout, then added the 'tabWidget' widget to that layout and set that layout as the layout of your QDialog.
def __init__(self, parent = None):
super(TabbedDialog, self).__init__(parent)
self.tabWidget = QTabWidget()
self.tabWidget.tab1 = QWidget()
self.tabWidget.tab2 = QWidget()
self.tabWidget.tab3 = QWidget()
self.tabWidget.addTab(self.tabWidget.tab1,"Tab 1")
self.tabWidget.addTab(self.tabWidget.tab2,"Tab 2")
self.tabWidget.addTab(self.tabWidget.tab3,"Tab 3")
self.tab1UI()
self.tab2UI()
self.tab3UI()
self.setWindowTitle("tab demo")
# Here is the addition to the code.
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.tabWidget)
self.setLayout(mainLayout)
I am trying to set up a window that has a text input & a combo box. At the moment I just want to see the text & the selection displayed under the appropriate widget.
I have used QVBoxLayout() as I will be adding more stuff later & thought it would be a simple way of laying out the window.
Unfortunately only the combo box ever gets displayed. The code:
from PyQt4 import QtCore, QtGui
import sys
class Polyhedra(QtGui.QMainWindow):
def __init__(self):
super(Polyhedra, self).__init__()
self.initUI()
def initUI(self):
# Poly names
self.pNames = QtGui.QLabel(self)
polyNameInput = QtGui.QLineEdit(self)
# polyName entry
polyNameInput.textChanged[str].connect(self.onChanged)
# Polytype selection
self.defaultPolyType = QtGui.QLabel("Random polyhedra", self)
polyType = QtGui.QComboBox(self)
polyType.addItem("Random polyhedra")
polyType.addItem("Spheres")
polyType.addItem("Waterman polyhedra")
polyType.activated[str].connect(self.onActivated)
# Layout
vbox = QtGui.QVBoxLayout()
vbox.addWidget(polyNameInput)
vbox.addWidget(self.pNames)
vbox.addWidget(polyType)
vbox.addWidget(self.defaultPolyType)
vbox.addStretch()
# Set up window
self.setGeometry(500, 500, 300, 300)
self.setWindowTitle('Pyticle')
self.show()
# Combo box
def onActivated(self, text):
self.defaultPolyType.setText(text)
self.defaultPolyType.adjustSize()
# Poly names
def onChanged(self, text):
self.pNames.setText(text)
self.pNames.adjustSize()
def main():
app = QtGui.QApplication(sys.argv)
ex = Polyhedra()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
So whats going on here? Am I missing some important directive to QVBoxLayout()?
Using Python 2.7 on Win 7 x64 machine with PyQt 4.
EDIT: Additional problem (still related to missing widgets)
I have amended the code following the clarification below. I then added more widgets when a certain option in the combobox is chosen (see below) but these widgets dont show. I attempted to add a child widget to 'widget' called 'ranPolyWidget' to take a numerical input.
# Combo box
def onActivated(self, text):
if text=="Random polyhedra":
self.randomSeedLbl = QtGui.QLabel("Seed: ", self)
randomSeed = QtGui.QLineEdit(self)
randomSeed.textChanged[str].connect(self.setSeed)
ranPolyWidget = QtGui.QWidget(self.widget)
rbox = QtGui.QVBoxLayout(ranPolyWidget)
rbox.addWidget(randomSeed)
self.layout().addWidget(ranPolyWidget)
self.show()
else:
self.defaultPolyType.setText(text)
self.defaultPolyType.adjustSize()
Same issue as before, no widgets. I am missing something pretty fundamental arent I?
You're forgetting to set it to the widget or main window, so since the QComboBox is the last one made, it's the only one displayed. Basically, everything is added to the layout, but the layout is "free-floating", and so it does not display properly. You need to bind the layout to a QWidget, which I do here. For most widgets, you can can do this by the QtGui.QVBoxLayout(widget) or by widget.setLayout(layout).
Alternatively, if you want multiple layouts on a widget, you can do have a parent layout and then add each child layout to the main layout.
EDIT: This is a better answer:
Make a widget, set layout to widget and set as central widget.
QMainWindow-s don't like you using the builtin layout or overriding it.
widget = QtGui.QWidget()
vbox = QtGui.QVBoxLayout(widget)
self.setCentralWidget(widget)
Old Answer:
self.layout().addLayout(vbox).
This should fix your issue:
Changes I made:
Since QMainWindow already has a layout, add in a widget (28G) and then set the VBoxLayout to the widget and add it to the main window.
from PyQt4 import QtCore, QtGui
import sys
class Polyhedra(QtGui.QMainWindow):
def __init__(self):
super(Polyhedra, self).__init__()
self.initUI()
def initUI(self):
# Poly names
self.pNames = QtGui.QLabel(self)
polyNameInput = QtGui.QLineEdit(self)
# polyName entry
polyNameInput.textChanged[str].connect(self.onChanged)
# Polytype selection
self.defaultPolyType = QtGui.QLabel("Random polyhedra", self)
polyType = QtGui.QComboBox(self)
polyType.addItem("Random polyhedra")
polyType.addItem("Spheres")
polyType.addItem("Waterman polyhedra")
polyType.activated[str].connect(self.onActivated)
# Layout
widget = QtGui.QWidget()
vbox = QtGui.QVBoxLayout(widget)
vbox.addWidget(polyNameInput)
vbox.addWidget(self.pNames)
vbox.addWidget(polyType)
vbox.addWidget(self.defaultPolyType)
vbox.addStretch()
# Set up window
self.setGeometry(500, 500, 300, 300)
self.setWindowTitle('Pyticle')
self.layout().addWidget(widget)
self.show()
# Combo box
def onActivated(self, text):
self.defaultPolyType.setText(text)
self.defaultPolyType.adjustSize()
# Poly names
def onChanged(self, text):
self.pNames.setText(text)
self.pNames.adjustSize()
def main():
app = QtGui.QApplication(sys.argv)
ex = Polyhedra()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
EDIT:
For adding new widgets, you should add them to the layout of the central widget and parent them to that widget.
Here's how I'd restructure your full code:
from PyQt4 import QtCore, QtGui
import sys
class CentralWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(CentralWidget, self).__init__(parent)
# set layouts
self.layout = QtGui.QVBoxLayout(self)
# Poly names
self.pNames = QtGui.QLabel(self)
polyNameInput = QtGui.QLineEdit(self)
# polyName entry
polyNameInput.textChanged[str].connect(self.onChanged)
# Polytype selection
self.defaultPolyType = QtGui.QLabel("Random polyhedra", self)
polyType = QtGui.QComboBox(self)
polyType.addItem("Random polyhedra")
polyType.addItem("Spheres")
polyType.addItem("Waterman polyhedra")
polyType.activated[str].connect(self.onActivated)
self.layout.addWidget(polyNameInput)
self.layout.addWidget(self.pNames)
self.layout.addWidget(polyType)
self.layout.addWidget(self.defaultPolyType)
self.layout.addStretch()
def onActivated(self, text):
'''Adds randSeed to layout'''
if text=="Random polyhedra":
self.randomSeedLbl = QtGui.QLabel("Seed: ", self)
randomSeed = QtGui.QLineEdit(self)
randomSeed.textChanged[str].connect(self.setSeed)
self.layout.addWidget(randomSeed)
else:
self.defaultPolyType.setText(text)
self.defaultPolyType.adjustSize()
# Poly names
def onChanged(self, text):
self.pNames.setText(text)
self.pNames.adjustSize()
class Polyhedra(QtGui.QMainWindow):
def __init__(self):
super(Polyhedra, self).__init__()
# I like having class attributes bound in __init__
# Not very Qt of me, but it's more
# so I break everything down into subclasses
# find it more Pythonic and easier to debug: parent->child
# is easy when I need to repaint or delete child widgets
self.central_widget = CentralWidget(self)
self.setCentralWidget(self.central_widget)
# Set up window
self.setGeometry(500, 500, 300, 300)
self.setWindowTitle('Pyticle')
self.show()
# Combo box
def onActivated(self, text):
'''Pass to child'''
self.central_widget.onActivated(text)
def main():
app = QtGui.QApplication(sys.argv)
ex = Polyhedra()
sys.exit(app.exec_())
if __name__ == '__main__':
main()