Python PyQt QScrollArea and QGridLayout (or any?) - python

I am trying to generate a Dialog with a stacked layout of GridLayout (of CheckBox's) and HLayout. Well, I did. But my grid got big (my HLayout is fine) but now I want a ScrollArea so as to not take up too much real estate. I have tried the following code .... and it generates a scroll view, but the size of the scroll view is the size of a button (the first ofc) in the HLayout. I want the scroll view to be the width of the Dialog, which nominally would be the minimum width of the HLayout. Additionally adding the scroll_view and scroll_viewWidget cause a QLayout exception to be raised, QLayout::addChildLayout: layout "" already has a parent. Any idea's?
class checkboxDialog(QtGui.QDialog) :
def __init__(self, headers, name) :
super(checkboxDialog, self).__init__()
self.checkerLayout = QtGui.QVBoxLayout()
self.checkerLayout.setMargin(1)
self.checkerLayout.setSpacing(2)
self.scroll_view = QtGui.QScrollArea(self)
self.scroll_view.setWidgetResizable(True)
self.scroll_viewWidget = QtGui.QWidget()
self.scroll_viewWidget.setGeometry(QtCore.QRect(0, 0, 600, 400))
self.scroll_view.setWidget(self.scroll_viewWidget)
self.checkerHlayout = QtGui.QHBoxLayout(self.scroll_viewWidget)
checksLayout = QtGui.QGridLayout()
checksLayout.setColumnStretch(90,7)
checksLayout.setMargin(1)
checksLayout.setSpacing(2)
self.cbList = []
index = 0
for row_index in range(90):
for column_index in range(7):
if index > len(headers)-1 : break
checkbox = QtGui.QCheckBox(headers[index][0:8], self)
checkbox.setToolTip("Chanel = {}".format(headers[index]))
self.cbList.append(checkbox)
# Hide the Phase channels for now ... not sure I shoudl even build the CheckBoxes
# But if I dont then the len(cbList) < len(data[0])
if headers[index][-1] == 'p' :
checkbox.hide()
checksLayout.addWidget(checkbox, row_index, column_index)
index += 1
self.checkerHlayout.addLayout(checksLayout)
self.buttonLayout = QtGui.QHBoxLayout()
self.buttonLayout.setMargin(1)
self.buttonLayout.setSpacing(2)
applyButton = QtGui.QPushButton("Apply")
nextButton = QtGui.QPushButton("Next")
nextAllButton = QtGui.QPushButton("NextAll")
prevButton = QtGui.QPushButton("Prev")
prevAllButton = QtGui.QPushButton("PrevAll")
clearButton = QtGui.QPushButton("Clear")
self.buttonLayout.addWidget(applyButton)
self.buttonLayout.addWidget(nextButton)
self.buttonLayout.addWidget(nextAllButton)
self.buttonLayout.addWidget(prevButton)
self.buttonLayout.addWidget(prevAllButton)
self.buttonLayout.addWidget(clearButton)
self.checkerLayout.addLayout(self.checkerHlayout)
self.checkerLayout.addLayout(self.buttonLayout)
self.setLayout(self.checkerLayout)
self.setObjectName(name)
self.setWindowTitle(name)
self.connect(applyButton, QtCore.SIGNAL('clicked()'), self.checked)
self.connect(nextButton, QtCore.SIGNAL('clicked()'), self.next_chn)
self.connect(nextAllButton, QtCore.SIGNAL('clicked()'), self.next_chnAll)
self.connect(prevButton, QtCore.SIGNAL('clicked()'), self.prev_chn)
self.connect(prevAllButton, QtCore.SIGNAL('clicked()'), self.prev_chnAll)
self.connect(clearButton, QtCore.SIGNAL('clicked()'), self.clear_chn)

I think this is what you wanted:
self.w2 = QtGui.QWidget(self)
self.w2.setLayout(self.buttonLayout)
self.checkerLayout.addWidget(self.w2)
self.checkerLayout.addWidget(self.scroll_view)
self.setLayout(self.checkerLayout)
(replacing the block with addLayout statements)

Related

QTable - get QSpinBox & QComboBox value

I am having trouble getting the current values from a QTable with QSpinBox & QCOmboBox widgets inserted in the table. I can get the value from Qlineedit, but nothing else except this one widget works. I have tried in several different ways but it keeps returning "None"
class MainWindow(QDialog):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("ptb")
# Main frame
self.main_layout = QVBoxLayout(self)
# Layout with 2 buttons and a radio button, part of main_layout
self.horizontalLayout = QHBoxLayout()
self.main_frame_tab_widget = QTabWidget()
self.main_layout.addWidget(self.main_frame_tab_widget)
self.horizontalLayout = QHBoxLayout()
self.main_layout.addLayout(self.horizontalLayout)
self.load_script_button = QPushButton("Load")
self.horizontalLayout.addWidget(self.load_script_button)
self.load_script_button.clicked.connect(self.load_script_button_clicked)
self.main_frame_tab_widget.addTab(self.targeting_tab(), "Targeting")
def load_script_button_clicked(self):
model = self.targeting_table.model()
targeting_table_content = {}
for row in range(model.rowCount()):
targeting_table_content[str(model.data(model.index(row, 1)))] = {
'danger': str(model.data(model.index(row, 2))),
'loot': str(model.data(model.index(row, 3))),
'only_if_trapped': str(model.data(model.index(row, 4)))
}
print(targeting_table_content)
def targeting_tab(self):
targeting_tab = QWidget()
# Main targeting tab vertical layout, which contains 2 other sublayouts
targeting_tab_main_layout = QHBoxLayout()
# Sub vertical layout containing a horizontal layout with 2 buttons and a table bellow the VBox
inner_left_vertical_layout = QVBoxLayout()
targeting_tab_main_layout.addLayout(inner_left_vertical_layout)
# Sub horizontal layout containing 2 buttons
inner_left_vertical_layouts_sub_horizontal_box = QHBoxLayout()
inner_left_vertical_layout.addLayout(inner_left_vertical_layouts_sub_horizontal_box)
# Adding creature
self.add_creature_button = QPushButton("Add creature")
inner_left_vertical_layouts_sub_horizontal_box.addWidget(self.add_creature_button)
self.add_creature_button.clicked.connect(self.add_creature_to_targeting_button_clicked)
# Deleting creature
self.delete_creature_button = QPushButton("Delete creature")
inner_left_vertical_layouts_sub_horizontal_box.addWidget(self.delete_creature_button)
self.delete_creature_button.clicked.connect(self.delete_creature_button_clicked)
self.targeting_table = QTableWidget()
self.targeting_table.setColumnCount(4)
self.targeting_table.setHorizontalHeaderLabels(['Name', 'Danger', 'Loot', 'Only if trapped'])
inner_left_vertical_layout.addWidget(self.targeting_table)
targeting_tab.setLayout(targeting_tab_main_layout)
return targeting_tab
def add_creature_to_targeting_button_clicked(self):
row_count = self.targeting_table.rowCount()
self.targeting_table.insertRow(row_count)
self.targeting_table.setItem(row_count, 0, QTableWidgetItem("input_mob_name"))
self.targeting_table.setCellWidget(row_count, 1, QSpinBox())
loot_combo_box = QComboBox()
loot_combo_box.addItems(["Yes", "No"])
self.targeting_table.setCellWidget(row_count, 2, loot_combo_box)
only_if_killed_combo_box = QComboBox()
only_if_killed_combo_box.addItems(["Yes", "No"])
self.targeting_table.setCellWidget(row_count, 3, only_if_killed_combo_box)
def delete_creature_button_clicked(self):
# Shows the number of delected rows bellow
rows = sorted(set(index.row() for index in self.targeting_table.selectedIndexes()))
# Removing the selected rows, if nothing is selected nothing happens
i = 0
for index in sorted(rows):
self.targeting_table.removeRow(index + i)
i = i - 1
if __name__ == '__main__':
# Create the Qt Application
app = QApplication(sys.argv)
# Create and show the form
form = MainWindow()
form.show()
# Run the main Qt loop
sys.exit(app.exec_())
With this when pressing the "load" button I get this result:
{'None': {'danger': 'None', 'loot': 'None', 'only_if_trapped': 'None'}}
If I change the way of obtaining the values from the Qtable the best I get is QlineEdit, but I can not get the Spinbox or the combobox values
The widgets placed above the view have nothing to do with the model, they are independent, so you should not use the model but rather the cellWidget() method to obtain the corresponding widget and through the widget obtain the information.
targeting_table_content = []
for row in range(self.targeting_table.rowCount()):
name = self.targeting_table.item(row, 0).text()
danger = self.targeting_table.cellWidget(row, 1).value()
loot = self.targeting_table.cellWidget(row, 2).currentText()
only_if_trapped = self.targeting_table.cellWidget(row, 3).currentText()
targeting_table_content.append(
{
"name": name,
"danger": danger,
"loot": loot,
"only_if_trapped": only_if_trapped,
}
)
print(targeting_table_content)

Python QTableWidget not displaying full width

I am an experienced (if rather rusty) Windows programmer. I am trying to create a partial logic simulation of a computer (Ferranti Argus 400) I designed in 1963 (yes I am that old!
I am however new to Python programming and am having a formatting problem using a QTableWidget.
I want to display this on the right alongside a set of controls for entering test data for a simulated function (and to use the QTableWidget to display the steps the simulation will run through to) for example show the working of the multiplier bit by bit.
I am trying to use a QHBoxLayout() as my outer container with two embedded Boxes. The left hand QVBox will contain my data entry for the simulation and the right hand box will contain a QTablewidget object with scrolling display of the state of the computer registers.
The QTableWidget works (the one below is a simplification) correctly until I add a Vbox on the left which contains the controls (one set is included here). The Table shrinks from its full width and positions itself at the right of the remaining space. I would like it on the left next to the other controls and for it to scroll if there is insufficient room (the target machine has 32*24 bit registers to display although I will be testing initially with 8 bits)
Screen with a group on left
enter image description here
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'PyQt5 simple window'
self.left = 10
self.top = 50
self.width = 800
self.height = 480
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
# Parent layout
self.central_Widget = QWidget(self)
self.setCentralWidget(self.central_Widget)
self.central_Layout = QHBoxLayout()
# Configure left panel as Vbox
self.leftpanel_Layout = QVBoxLayout()
#
self.leftpanel_Layout.addWidget(DataSelectionGroup("Data entry mode"))
#
# Add stretch to bottom of panel
self.leftpanel_Layout.addStretch(0)
self.rightpanel_Layout = QVBoxLayout()
self.myLogTable = LogTablex()
self.rightpanel_Layout.addWidget(self.myLogTable)
self.setLayout(self.rightpanel_Layout)
# Add left panel layout to central layout
# uncomment these lines to see the unwanted behaviour
#self.central_Layout.addLayout(self.leftpanel_Layout)
#self.central_Layout.addStretch(0)
self.setLayout(self.central_Layout)
self.central_Layout.addLayout(self.rightpanel_Layout)
self.setLayout(self.central_Layout)
self.central_Widget.setLayout(self.central_Layout)
self.setWindowTitle("Demo")
self.show()
class DataSelectionGroup(QGroupBox):
""" Create a group of Radio Buttons to choose type of data entry """
def __init__(self, title):
super().__init__(title)
self.buttonLayout = QVBoxLayout()
# add radio buttons to choose which mode of data entry to use
self.radio1 = QRadioButton("&Binary")
self.buttonLayout.addWidget(self.radio1)
self.radio1.setChecked(True)
self.radio2 = QRadioButton("Decimal &Fraction")
self.buttonLayout.addWidget(self.radio2)
self.radio3 = QRadioButton("Decimal &Integer")
self.buttonLayout.addWidget(self.radio3)
self.setLayout(self.buttonLayout)
class LogTablex(QTableWidget):
def __init__(self, WordLength:int = 24):
super().__init__()
self.WordLength = WordLength
self.initTable(["Note", "X", "Q", "N", "C", "O"])
def initTable(self, headerlist):
font = QFont()
font.setFamily = "Courier New"
font.setPointSize(8)
self.setFont(font)
self.horizontalHeader().setStyleSheet("QHeaderView::section { background-color:lightgrey; }")
self.setColumnCount(len(headerlist))
self.setHorizontalHeaderLabels(headerlist)
self.setRowCount(0)
self.start_newrow()
self.str = '0' * self.WordLength + ' '
self.setCellWidget(0, 0, QLabel("note"))
self.setCellWidget(0, 1, QLabel(self.str))
self.setCellWidget(0, 2, QLabel(self.str))
self.setCellWidget(0, 3, QLabel(self.str))
self.setCellWidget(0, 4, QLabel("1"))
self.setCellWidget(0, 5, QLabel("1"))
self.verticalHeader().setDefaultSectionSize(22)
self.horizontalHeader().setSectionResizeMode(3)
self.resizeColumnsToContents()
def start_newrow(self, note:str = "new note "):
self.insertRow(self.rowCount())
self.setCellWidget(self.rowCount() - 1, 0, QLabel(note))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
This version produces the first image. If you uncomment the two lines shown it produces the second version. I have battled with this for a while and I am unable to fathom how to get the right hand table to behave. I am hoping that someone can shed light on it.
I am using PyQt5 with the latest version of Python downloaded about 1 week ago. I am running on Windows 10.
This is my first post here. I hope it is formatted correctly
First of all I recommend you execute a script in the CMD or terminal because many times the IDEs hide us errors like for example if I execute your code I get the following message:
QWidget::setLayout: Attempting to set QLayout "" on App "", which already has a layout
QWidget::setLayout: Attempting to set QLayout "" on App "", which already has a layout
QWidget::setLayout: Attempting to set QLayout "" on App "", which already has a layout
And that error because QMainWindow is a special widget that has a preset layout as shown in the following image:
And in your case you are trying to replace it, the correct thing is to set the layout to the centralwidget.
Going to the problem it seems that you are adding layouts repeatedly and that causes the problem, so I have improved your code to establish the positions (I recommend not to make the layouts attributes of the class since they are generally not reused)
from PyQt5 import QtCore, QtGui, QtWidgets
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.title = 'PyQt5 simple window'
self.left, self.top, self.width, self.height = 10, 50, 800, 480
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
# Parent layout
self.central_Widget = QtWidgets.QWidget()
self.setCentralWidget(self.central_Widget)
central_Layout = QtWidgets.QHBoxLayout(self.central_Widget)
leftpanel_Layout = QtWidgets.QVBoxLayout()
leftpanel_Layout.addWidget(DataSelectionGroup("Data entry mode"))
leftpanel_Layout.addStretch()
rightpanel_Layout = QtWidgets.QVBoxLayout()
self.myLogTable = LogTablex()
rightpanel_Layout.addWidget(self.myLogTable)
central_Layout.addLayout(leftpanel_Layout)
central_Layout.addLayout(rightpanel_Layout)
self.setWindowTitle("Demo")
self.show()
class DataSelectionGroup(QtWidgets.QGroupBox):
""" Create a group of Radio Buttons to choose type of data entry """
def __init__(self, title):
super().__init__(title)
buttonLayout = QtWidgets.QVBoxLayout(self)
# add radio buttons to choose which mode of data entry to use
self.radio1 = QtWidgets.QRadioButton("&Binary")
buttonLayout.addWidget(self.radio1)
self.radio1.setChecked(True)
self.radio2 = QtWidgets.QRadioButton("Decimal &Fraction")
buttonLayout.addWidget(self.radio2)
self.radio3 = QtWidgets.QRadioButton("Decimal &Integer")
buttonLayout.addWidget(self.radio3)
class LogTablex(QtWidgets.QTableWidget):
def __init__(self, WordLength:int = 24):
super().__init__()
self.WordLength = WordLength
self.initTable(["Note", "X", "Q", "N", "C", "O"])
def initTable(self, headerlist):
font = QtGui.QFont("Courier New", 8)
self.setFont(font)
self.horizontalHeader().setStyleSheet("QHeaderView::section { background-color:lightgrey; }")
self.setColumnCount(len(headerlist))
self.setHorizontalHeaderLabels(headerlist)
self.setRowCount(0)
self.start_newrow()
text = '0' * self.WordLength + ' '
for i, val in enumerate(("note", text, text, text, "1", "1",)):
self.setCellWidget(0, i, QtWidgets.QLabel(val))
self.verticalHeader().setDefaultSectionSize(22)
self.horizontalHeader().setSectionResizeMode(3)
self.resizeColumnsToContents()
def start_newrow(self, note: str = "new note "):
self.insertRow(self.rowCount())
self.setCellWidget(self.rowCount() - 1, 0, QtWidgets.QLabel(note))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Update:
For the first layout to occupy the minimum space and the other one to expand, you must add a stretch of 1 when you add the rightpanel_Layout, so change it to:
central_Layout.addLayout(leftpanel_Layout)
central_Layout.addLayout(rightpanel_Layout, stretch=1) # <---
Also it is not necessary to establish fixed anchors, the layouts will do the work for you:
class DataEntryGroupLayout(QtWidgets.QGroupBox):
def __init__(self, title):
super().__init__(title)
_form = QtWidgets.QFormLayout(self)
# Add the form controls to the group box = list required
_pairlist = ["x value", "n value"]
for _pair in _pairlist:
_label = QtWidgets.QLabel(_pair)
_value = QtWidgets.QLineEdit()
_form.addRow(_label, _value)

Dynamically add and remove a Layout when one of the Radio Button is Selected

I m able to dynamically add a layout to QHBoxLayout in pyqt , however I m unable to remove them once added.
Main aim is to dynamically add and remove a layout based on the Radio Button selected.
def SearchTab(self):
self.layout = QVBoxLayout()
button_layout = QHBoxLayout()
radio_button_1 = QRadioButton("Search")
radio_button_2 = QRadioButton("Update")
button_layout.addWidget(radio_button_1)
button_layout.addWidget(radio_button_2)
self.layout.addItem(button_layout)
radio_button_1.toggled.connect(lambda :self.SelectButtonCheck(radio_button_1))
radio_button_1.toggled.connect(lambda :self.UpdateButtonCheck(radio_button_2))
self.setTabText(0,"Search")
self.tab1.setLayout(self.layout)
def SelectButtonCheck(self,b):
if b.text() == "Search":
if b.isChecked():
print(b.text()+ "is selected")
self.pg_details = pgd.PGDetails()
layout = self.pg_details.returnLayout()
self.layout.addLayout(layout)
def UpdateButtonCheck(self,b):
if b.text() == "Update":
if b.isChecked():
print(b.text()+ " is selected")
for i in range(self.layout.count()):
print(self.layout.itemAt(i))
temp_layout = self.layout.itemAt(i)
widget = temp_layout.widget()
temp_layout.removeItem(temp_layout)
if widget is not None:
widget.deleteLater()
Initial Screen-
Currently I m able to add the layout when "Search" Radio Button is selected --
But Nothing happens when I select "Update" RadioButton
Also find the layouts that have been added-
for i in range(self.layout.count()):
print(self.layout.itemAt(i))
<PyQt5.QtWidgets.QHBoxLayout object at 0x1180ec438>
<PyQt5.QtWidgets.QFormLayout object at 0x1180ff828>
Layouts are being added but not getting removed.
Any leads would be helpful , in what I m missing here
I was able to solve this. Took me a while but understood what is the arrangement of widgets within the layouts.
I assumed removing the layout will cascade delete the widgets itself.
I used the below function to remove the layout and its widgets corresponding to it.
def SearchTab(self):
self.layout = QVBoxLayout()
button_layout = QHBoxLayout()
radio_button_1 = QRadioButton("Search")
radio_button_2 = QRadioButton("Update")
button_layout.addWidget(radio_button_1)
button_layout.addWidget(radio_button_2)
self.layout.addItem(button_layout)
#createDB()
radio_button_1.toggled.connect(lambda :self.SelectButtonCheck(radio_button_1,self.layout))
radio_button_1.toggled.connect(lambda :self.UpdateButtonCheck(radio_button_2,self.layout))
#layout.addRow("Address",QLineEdit())
self.setTabText(0,"Search")
update_layout = QHBoxLayout()
#update_layout.set
#update_btn = QDialogButtonBox(QDialogButtonBox)
#update_btn.setAlignment(Qt.AlignBottom)
update_layout.setAlignment(QtCore.Qt.AlignTop)
update_btn = QPushButton('Update')
reset_btn = QPushButton('Reset')
#self.layout.addRow(update_layout)
update_layout.addWidget(update_btn)
update_layout.addWidget(reset_btn)
update_btn.clicked.connect(self.createDB)
self.tab1.setLayout(self.layout)
def SelectButtonCheck(self,b,stacklayout):
if b.text() == "Search":
if b.isChecked():
print(b.text()+ "is selected")
self.pg_details = pgd.PGDetails()
layout = self.pg_details.returnLayout()
self.layout.addLayout(layout)
def removeLayout(self,layout):
for i in range(layout.count()):
temp_layout = layout.itemAt(i)
if temp_layout is not None:
widget = temp_layout.widget()
if widget is not None:
widget.deleteLater()
else:
return
if temp_layout.layout() is not None:
self.removeLayout(temp_layout.layout())
def removeFormLayout(self,layout):
if layout is not None:
for i in range(layout.count()):
temp_layout = layout.itemAt(i)
if isinstance(temp_layout.layout(),type(QFormLayout())):
self.removeLayout(temp_layout.layout())
else:
next
else:
return
def UpdateButtonCheck(self,b,stacklayout):
if b.text() == "Update":
if b.isChecked():
print(b.text()+ " is selected")
self.removeFormLayout(stacklayout)
The removeFormLayout function picks out the formlayout that I added with the Search radio button and removeLayout removes all the widgets under it as well.
Open to suggestions and improvements in the method used, I tried it with a couple of layout removals other then FormLayout as well. Currently it is working fine.
Also is anybody aware of how to align the HBoxLayout at the top , the radio button starts from the middle again , I want to align them at the top of the screen
Another way is to do the following. QWidget and thus QGroupBox have a show/hide option.
Note, its best to always hide first, otherwise things get wonky
I have a test function that has the following control logic
if isOn:
self.gb1.hide()
self.gb2.show()
else:
self.gb2.hide()
self.gb1.show()
I created a layout that contains both group boxes above. see the sample logic below. I am sure there is a way to do this without storing the variables in the window class.
def create_layout(self):
ly = QHBoxLayout()
self.gb1 = self.create_gb_test1()
self.gb2 = self.create_gb_test2()
ly.addWidget(self.gb1)
ly.addWidget(self.gb2)
return ly
def create_gb_test1(self):
my_name = inspect.currentframe().f_code.co_name
gb = QGroupBox("Find")
btn_find = QPushButton()
ly_horiz = QHBoxLayout()
ly_horiz.addWidget(QLabel("Find:"))
ly_horiz.addWidget(QLineEdit("Some Text", ))
ly_horiz.addWidget(btn_find)
self.ly_find_only = ly_horiz
gb.setLayout(ly_horiz)
return gb
def btn_open_click(self):
pass
def create_gb_test2(self):
my_name = inspect.currentframe().f_code.co_name
gb = QGroupBox("View")
btn_open = QPushButton
cbo = QComboBox()
cbo.addItems(['a', 'b'])
ly_horiz = QHBoxLayout()
ly_horiz.addWidget(QLabel("Find:"))
ly_horiz.addWidget(cbo)
ly_horiz.addWidget(btn_open)
self.ly_find_only = ly_horiz
gb.setLayout(ly_horiz)
return gb

Pyqt5 addStretch in between widgets?

I am using a QVBox layout and there are two widgets and a dynamic layout 'layout2' in the layout. Widget1 is fixed on top Widget3 is fixed at the bottom and widget2 is dynamic widget. layout2 is deleted and added each time. The problem here is I am not able to position the widget3 at the bottom as layout2 layout is deleted Widget3 moves to the top. Below is the sample code.
class Screen(QWidget):
def __init__(self):
super(Screen, self).__init__()
self.main_layout = QVBoxLayout()
widget1 = QPushButton("Text1")
#self.widget2 = QWidget()
widget3 = QLabel("Text3")
self.widget2_layout = QHBoxLayout()
widget2_label = QLabel("text2")
self.widget2_layout.addWidget(widget2_label)
#self.widget2.setLayout(self.widget2_layout)
self.main_layout.addWidget(widget1,Qt.AlignTop)
self.main_layout.addLayout(self.widget2_layout)
self.main_layout.addWidget(widget3,Qt.AlignBottom)
widget1.clicked.connect(self.change_widget2)
self.setLayout(self.main_layout)
self.show()
def clearLayout(self,layout):
item = layout.takeAt(0)
while item:
w = item.widget()
if w:
w.deleteLater()
lay = item.layout()
if lay:
self.clearLayout(item.layout())
item = layout.takeAt(0)
def change_widget2(self):
self.clearLayout(self.widget2_layout)
self.widget2_layout = QHBoxLayout()
widget2_label = QLabel("text changed")
self.widget2_layout.addWidget(widget2_label)
self.main_layout.addLayout(self.widget2_layout)
app = QApplication(sys.argv)
Gui = Screen()
sys.exit(app.exec_())
I have tried addstretch, dummy additional layout and nothing worked.
If you only want to change the widget that is in the second position it is not necessary to delete create a new layout, it is only necessary to reuse it, in the following example we see how the widget is changing:
class Screen(QWidget):
def __init__(self):
super(Screen, self).__init__()
self.setLayout(QVBoxLayout())
widget1 = QPushButton("Text1", self)
widget3 = QLabel("Text3", self)
self.widget2_layout = QHBoxLayout()
self.change_widget2()
self.layout().addWidget(widget1)
self.layout().addLayout(self.widget2_layout)
self.layout().addWidget(widget3)
widget1.clicked.connect(self.change_widget2)
def clearLayout(self, layout):
item = layout.takeAt(0)
while item:
w = item.widget()
if w:
w.deleteLater()
lay = item.layout()
if lay:
self.clearLayout(item.layout())
item = layout.takeAt(0)
def change_widget2(self):
self.clearLayout(self.widget2_layout)
# change the widget.
import random
widgets = [QLabel, QLineEdit, QPushButton]
widget2 = widgets[random.randint(0, len(widgets)-1)]("widget2", self)
self.widget2_layout.addWidget(widget2)

Wrong widget order using vbox layout PyQt

I am trying to put a QLabel widget on top of (ie before) a QLineEdit widget edit.
But it keeps appearing after the QLineEdit widget. My code,
class CentralWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(CentralWidget, self).__init__(parent)
# set layouts
self.layout = QtGui.QVBoxLayout(self)
# Flags
self.randFlag = False
self.sphereFlag = False
self.waterFlag = False
# Poly names
self.pNames = QtGui.QLabel("Import file name", self) # label concerned
self.polyNameInput = QtGui.QLineEdit(self) # line edit concerned
# Polytype selection
self.polyTypeName = QtGui.QLabel("Particle type", self)
polyType = QtGui.QComboBox(self)
polyType.addItem("")
polyType.addItem("Random polyhedra")
polyType.addItem("Spheres")
polyType.addItem("Waterman polyhedra")
polyType.activated[str].connect(self.onActivated)
self.layout.addWidget(self.pNames)
self.layout.addWidget(self.polyNameInput)
self.layout.addWidget(self.pNames)
self.layout.addWidget(self.polyTypeName)
self.layout.addWidget(polyType)
self.layout.addStretch()
def onActivated(self, text):
# Do loads of clever stuff that I'm not at liberty to share with you
class Polyhedra(QtGui.QMainWindow):
def __init__(self):
super(Polyhedra, self).__init__()
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):
self.central_widget.onActivated(text)
def main():
app = QtGui.QApplication(sys.argv)
poly = Polyhedra()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The window I get is below.
What am I missing? I thought QVbox allowed to stack things vertically in the order that you add the items to the main widget. (Are these sub-widget objects called widgets?)
The problem is because you are adding self.pNames label to layout twice.
#portion of your code
...
self.layout.addWidget(self.pNames) # here
self.layout.addWidget(self.polyNameInput)
self.layout.addWidget(self.pNames) # and here
self.layout.addWidget(self.polyTypeName)
self.layout.addWidget(polyType)
self.layout.addStretch()
...
The first time you add the QLabel, it gets added before the LineEdit and when you add it second time, it just moves to the bottom of LineEdit. This happens because there is only one object of QLabel which is self.pNames. It can be added to only one location. If you want to use two labels, consider creating two separate objects of QLabel

Categories