PyQt5 adding add and remove widget buttons beside every tab - python

I want to add buttons to the tabs in the QTabWidget.
My first instinct was to try to get the position of each tab and then add the button ontop of the tab, but I cant figure out how to get the position of the tab! Only the entire tab widget.
I was looking around and now what I think I should do is make a custom TabBar class where I can place buttons on each tab like the standard Qt close button.
Anyone here who can send me in the right direction?

Okay so I found out how to make it work like I want it. It was actually quite simple, I made a QWidget class with a horizontal layout and two buttons and passed it to the setTabButton function. For anyone interested see the code below.
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class TabExample(QMainWindow):
def __init__(self):
super(TabExample, self).__init__()
self.setWindowTitle("Tab example")
# Create widgets
self.tab_widget = QtWidgets.QTabWidget()
self.setCentralWidget(self.tab_widget)
# Label's to fill widget
self.label1 = QtWidgets.QLabel("Tab 1")
self.label2 = QtWidgets.QLabel("Tab 2")
# Adding tab's
self.tab_widget.addTab(self.label1, "Tab 1")
self.tab_widget.addTab(self.label2, "Tab 2")
# Tab button's
self.right = self.tab_widget.tabBar().RightSide
self.tab_widget.tabBar().setTabButton(0, self.right, TabButtonWidget())
self.tab_widget.tabBar().setTabButton(1, self.right, TabButtonWidget())
# Tab settings
self.tab_widget.tabBar().setMovable(True)
self.show()
class TabButtonWidget(QtWidgets.QWidget):
def __init__(self):
super(TabButtonWidget, self).__init__()
# Create button's
self.button_add = QtWidgets.QPushButton("+")
self.button_remove = QtWidgets.QPushButton("-")
# Set button size
self.button_add.setFixedSize(16, 16)
self.button_remove.setFixedSize(16, 16)
# Create layout
self.layout = QtWidgets.QVBoxLayout()
self.layout.setSpacing(0)
self.layout.setContentsMargins(0, 0, 0, 0)
# Add button's to layout
self.layout.addWidget(self.button_add)
self.layout.addWidget(self.button_remove)
# Use layout in widget
self.setLayout(self.layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
gui = TabExample()
sys.exit(app.exec_())

Related

What is the difference between QLayout's setAlignment(QWidget, Alignment), setAlginment(QLayout, Alignment) and setAlginment(Alignment)? (PyQt5)

In the following code:
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QTableWidget, QPushButton
class Window(QtWidgets.QMainWindow):
def __init__(self, method):
super(Window, self).__init__()
mainWidget = QWidget()
mainLayout = QHBoxLayout(mainWidget)
table = QTableWidget(10, 3)
button1 = QPushButton("Play")
button2 = QPushButton("Cancel")
mainLayout.addWidget(table)
mainLayout.addWidget(button1)
mainLayout.addWidget(button2)
if (method == 1):
rtnValue = mainLayout.setAlignment(button1, Qt.AlignTop)
print("Method 1:", rtnValue)
elif (method == 2):
rtnValue = mainLayout.setAlignment(mainLayout, Qt.AlignTop)
print("Method 2:", rtnValue)
else:
rtnValue = mainLayout.setAlignment(Qt.AlignTop)
print("Method X:", rtnValue)
self.setCentralWidget(mainWidget)
self.show()
if __name__ == "__main__":
print("python QLayoutAlignment.py[ <MethodToUse=1>")
app = QApplication(sys.argv)
method = 1 if (len(sys.argv) < 2) else int(sys.argv[1])
GUI = Window(method)
sys.exit(app.exec_())
when I call the program like below with mainLayout.setAlignment(button1, Qt.AlignTop) being called, it works as expected with the "Play" button aligned at the top and "Cancel" button aligned at the center vertically. I also found the documentation for bool QLayout::setAlignment(QWidget *w, Qt::Alignment alignment) although in Qt.
python QLayoutAlignment.py 1
However when I call the the program like below with mainLayout.setAlignment(mainLayout, Qt.AlignTop) being called, it does not seem to work. All the buttons are vertically center aligned. I interpreted the Qt documentation of bool QLayout::setAlignment(QLayout *l, Qt::Alignment alignment)) as "it align all the added widget of the layout to the set alignment". So what does this function actually do (when is it used)?
python QLayoutAlignment.py 2
Lastly, I also saw another example from Center and top align a QVBoxLayout. When I call the program like below with mainLayout.setAlignment(Qt.AlignTop) being called, it also does not work with all the buttons vertically center aligned. For this one I could not find its documentation. So what does this function actually do (when is it used) and where can I find its documentation?
python QLayoutAlignment.py 3
The .setAlignment method which accepts a layout is used for aligning sub-layouts, that is child layouts you've added to the parent layout using .addLayout.
Below is a little demo based on your code.
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QTableWidget, QPushButton
class Window(QtWidgets.QMainWindow):
def __init__(self, method=0):
super(Window, self).__init__()
mainWidget = QWidget()
self.mainLayout = QHBoxLayout(mainWidget)
table = QTableWidget(10, 3)
self.button1 = QPushButton("Play")
self.button2 = QPushButton("Cancel")
self.subLayout = QHBoxLayout()
buttona1 = QPushButton("1")
buttona1.clicked.connect(self.clicked1)
buttona2 = QPushButton("2")
buttona2.clicked.connect(self.clicked2)
buttona3 = QPushButton("3")
buttona3.clicked.connect(self.clicked3)
buttona4 = QPushButton("4")
buttona4.clicked.connect(self.clicked4)
self.subLayout.addWidget(buttona1)
self.subLayout.addWidget(buttona2)
self.subLayout.addWidget(buttona3)
self.subLayout.addWidget(buttona4)
self.mainLayout.addWidget(table)
self.mainLayout.addWidget(self.button1)
self.mainLayout.addWidget(self.button2)
self.mainLayout.addLayout(self.subLayout)
self.setCentralWidget(mainWidget)
self.show()
def clicked1(self):
rtnValue = self.mainLayout.setAlignment(self.button1, Qt.AlignTop)
print("Method 1:", rtnValue)
def clicked2(self):
rtnValue = self.mainLayout.setAlignment(self.mainLayout, Qt.AlignTop)
print("Method 2:", rtnValue)
def clicked3(self):
rtnValue = self.mainLayout.setAlignment(Qt.AlignTop)
print("Method 3:", rtnValue)
def clicked4(self):
rtnValue = self.mainLayout.setAlignment(self.subLayout, Qt.AlignTop)
print("Method 4:", rtnValue)
if __name__ == "__main__":
print("python QLayoutAlignment.py[ <MethodToUse=1>")
app = QApplication(sys.argv)
method = 1 if (len(sys.argv) < 2) else int(sys.argv[1])
GUI = Window(method)
sys.exit(app.exec_())
You'll notice if you trigger this self.mainLayout.setAlignment(self.mainLayout, Qt.AlignTop) the return value is False. This is telling you that the layout you're aligning could not be found in the current layout. Since you're calling .setAlignment on mainLayout the layout you're affecting must be in that layout.
In the 4th method, I've added a sub-layout, and as you can see this ( rtnValue = self.mainLayout.setAlignment(self.subLayout, Qt.AlignTop)) works as expected and returns True.
First of all, it's important to understand that the Qt layout system works by using layout items (see QLayoutItem), which are abstract items that are used as virtual containers for objects: widgets, spacers and layouts (when nested layouts are used). Every QLayout is, in fact, a subclass of QLayoutItem.
Using setAlignment means setting the alignment of the specified layout item:
layout.setAlignment(item, alignment) sets the alignment of item, which has to be directly contained in layout;
layout.setAlignment(alignment) sets the alignment of layout related to its parent layout; note that this does not mean that items inside layout will use the specified alignment;
Your second case, mainLayout.setAlignment(mainLayout, Qt.AlignTop), does not work and returns False because mainLayout is, obviously, not "contained" in mainLayout. In fact, if you carefully read the documentation, it says:
returns true if w/l is found in this layout (not including child layouts);
In your third case, you don't see any result because mainLayout is the top layout for the widget, and since there's no parent layout the alignment seems to be ignored. As specified above, using layout.setAlignment(alignment) does not set the alignment of child items, but only of the layout item of layout. If you add that mainLayout to another layout, you will see that the alignment is respected for the layout.
Setting the layout alignment is rarely used, also because it's often counterintuitive: one might led to believe that setting the alignment of a layout will align its contents, but that's not the case.
To clarify, consider that setting the layout alignment is almost the same as creating a widget with that layout, and adding that widget with the specified alignment. With that in mind, it makes more sense: you're not aligning the contents of the widget, but the widget itself.
Consider the following example: besides the table on the left (used for comparison), I'm adding a layout on the left by specifying its alignment, then I'm adding a widget on the right by specifying the alignment of the widget for the main layout. As you can see, they appear exactly the same.
from PyQt5 import QtCore, QtWidgets
import sys
app = QtWidgets.QApplication(sys.argv)
test = QtWidgets.QWidget()
mainLayout = QtWidgets.QHBoxLayout(test)
# a very tall table to show the difference in alignment
mainLayout.addWidget(QtWidgets.QTableView(minimumHeight=300))
leftLayout = QtWidgets.QHBoxLayout()
# setting the alignment of leftLayout relative to mainLayout
leftLayout.setAlignment(QtCore.Qt.AlignTop)
leftLayout.addWidget(QtWidgets.QTableView(maximumHeight=100))
leftLayout.addWidget(QtWidgets.QPushButton())
mainLayout.addLayout(leftLayout)
rightWidget = QtWidgets.QWidget()
# adding the widget to mainLayout by aligning it on top as with leftLayout
mainLayout.addWidget(rightWidget, alignment=QtCore.Qt.AlignTop)
rightLayout = QtWidgets.QHBoxLayout(rightWidget)
rightLayout.addWidget(QtWidgets.QTableView(maximumHeight=100))
rightLayout.addWidget(QtWidgets.QPushButton())
test.show()
sys.exit(app.exec_())
Finally, if you want to align widgets, you either specify the alignment for each widget, or you add nested layout.
When many widgets are going to be added with the same alignment, the nested layout is usually the best solution: in your case, add a vertical layout to the main layout, then add horizontal layout to the vertical for the buttons, and add a stretch to the vertical to "push" the horizontal layout on top.
Alternatively, you can use a grid layout and eventually use spacers to ensure that the widgets are "aligned" as required.
from PyQt5 import QtCore, QtWidgets
import sys
app = QtWidgets.QApplication(sys.argv)
test = QtWidgets.QWidget()
mainLayout = QtWidgets.QHBoxLayout(test)
class Button(QtWidgets.QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setSizePolicy(
QtWidgets.QSizePolicy.Preferred,
QtWidgets.QSizePolicy.Preferred
)
noAlignGroup = QtWidgets.QGroupBox('no alignment')
mainLayout.addWidget(noAlignGroup)
noAlignLayout = QtWidgets.QHBoxLayout(noAlignGroup)
noAlignLayout.addWidget(QtWidgets.QTableView())
noAlignLayout.addWidget(Button())
noAlignLayout.addWidget(Button())
widgetAlignGroup = QtWidgets.QGroupBox('addWidget(widget, alignment)')
mainLayout.addWidget(widgetAlignGroup)
widgetAlignLayout = QtWidgets.QHBoxLayout(widgetAlignGroup)
widgetAlignLayout.addWidget(QtWidgets.QTableView())
widgetAlignLayout.addWidget(Button(), alignment=QtCore.Qt.AlignTop)
widgetAlignLayout.addWidget(Button(), alignment=QtCore.Qt.AlignTop)
layoutAlignGroup = QtWidgets.QGroupBox('nestedLayout.setAlignment()')
mainLayout.addWidget(layoutAlignGroup)
layoutAlignLayout = QtWidgets.QHBoxLayout(layoutAlignGroup)
layoutAlignLayout.addWidget(QtWidgets.QTableView())
buttonLayout = QtWidgets.QHBoxLayout()
layoutAlignLayout.addLayout(buttonLayout)
buttonLayout.setAlignment(QtCore.Qt.AlignTop)
buttonLayout.addWidget(Button())
buttonLayout.addWidget(Button())
stretchGroup = QtWidgets.QGroupBox('nestedLayout + stretch')
mainLayout.addWidget(stretchGroup)
stretchLayout = QtWidgets.QHBoxLayout(stretchGroup)
stretchLayout.addWidget(QtWidgets.QTableView())
rightLayout = QtWidgets.QVBoxLayout()
stretchLayout.addLayout(rightLayout)
buttonLayout = QtWidgets.QHBoxLayout()
rightLayout.addLayout(buttonLayout)
buttonLayout.addWidget(Button())
buttonLayout.addWidget(Button())
rightLayout.addStretch()
gridAlignGroup = QtWidgets.QGroupBox('grid + spacer')
mainLayout.addWidget(gridAlignGroup)
gridLayout = QtWidgets.QGridLayout(gridAlignGroup)
gridLayout.addWidget(QtWidgets.QTableView(), 0, 0, 2, 1)
gridLayout.addWidget(Button(), 0, 1)
gridLayout.addWidget(Button(), 0, 2)
spacer = QtWidgets.QSpacerItem(1, 50, vPolicy=QtWidgets.QSizePolicy.Expanding)
gridLayout.addItem(spacer, 1, 1)
test.show()
sys.exit(app.exec_())

Using QScrollArea collapses children widgets

I am trying to create a dynamic GUI with multiple Groupbox objects in a QVBoxLayout. As there are a lot of them, I will be needing a scroll area to make them available to the end user.
So I tried to change to top widget of this tab from a QWidget to a QScrollArea.
Before the change:
This is the kind of result I want but with a scroll bar because the window is too high.
After the change to QScrollArea:
My GroupBoxs are now "collapsed" and there is not scrollbar. I tried setting their size but it is not adequate because they are not fixed. I searched the documentation and tried to use WidgetResizable or I tried to set a fixed height or the sizehint but nothing worked as I wanted.
After creating the the Groupbox, the sizeHint for my QScrollArea is already very low (around 150px of height) so I think I'm missing a parameter.
It would be complicated to provide code as it is intricate. If necessary I could recreate the problem in a simpler way.
How to reproduce:
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import *
import sys
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
v_layout = QVBoxLayout()
scroll_area = QScrollArea()
self.layout().addWidget(scroll_area)
scroll_area.setLayout(v_layout)
# v_layout.setSizeConstraint(QLayout.SetMinimumSize)
for i in range(50):
box = QGroupBox()
grid = QGridLayout()
box.setLayout(grid)
grid.addWidget(QLabel("totototo"), 0, 0)
grid.addWidget(QLineEdit(), 1, 0)
grid.addWidget(QPushButton(), 2, 0)
v_layout.addWidget(box)
self.show()
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Uncommenting # v_layout.setSizeConstraint(QLayout.SetMinimumSize) allows the content of the group boxes to deploy and fixes the first part of the issue. But there is still not scroll bar.
You have 2 errors:
A widget should not be added to the layout of a QMainWindow, but the setCentralWidget method should be used.
You should not add the layout to the QScrollArea but use a widget as a container for the other widgets, also if you use layouts then you have to activate the widgetResizable property.
Considering the above, the solution is:
def initUI(self):
scroll_area = QScrollArea(widgetResizable=True)
self.setCentralWidget(scroll_area)
container = QWidget()
scroll_area.setWidget(container)
v_layout = QVBoxLayout(container)
for i in range(50):
box = QGroupBox()
grid = QGridLayout()
box.setLayout(grid)
grid.addWidget(QLabel("totototo"), 0, 0)
grid.addWidget(QLineEdit(), 1, 0)
grid.addWidget(QPushButton(), 2, 0)
v_layout.addWidget(box)
self.show()

unable to re-open a window on pyqt5 pyqtlet

I have a basic GUI window, created with pyqt5 package, that contain a button that once clicked opens a map window thanks to Python's pyqtlet package.
My program does open the map window on first click, but here my issue:
If I close the map window and click again on the button it only show me a white window.
SOURCE CODE
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QGridLayout
from PyQt5.QtCore import Qt
from pyqtlet import L, MapWidget
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# set window title
self.setWindowTitle('Windowtitle')
# set layout
self.layout = QGridLayout()
self.layout.setAlignment(Qt.AlignCenter)
# create button to show the map
self.show_map_button = QPushButton('Show Map')
self.show_map_button.clicked.connect(self.show_map)
# add button to layout
self.layout.addWidget(self.show_map_button, 0, 1)
# show layout
self.setLayout(self.layout)
self.my_map = None
def show_map(self):
# create map window instance
self.my_map = MapWindow()
class MapWindow(QWidget):
def __init__(self):
# Setting up the widgets and layout
super().__init__()
self.mapWidget = MapWidget()
self.layout = QGridLayout()
self.layout.addWidget(self.mapWidget)
self.setLayout(self.layout)
# Working with the maps with pyqtlet
self.map = L.map(self.mapWidget)
self.map.setView([12.97, 77.59], 10)
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(self.map)
self.marker = L.marker([12.934056, 77.610029])
self.marker.bindPopup('Maps are a treasure.')
self.map.addLayer(self.marker)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
I click the button for the first time (works as expected):
The second time I click it doesn't work as expected:
Please, can you help me find out where the issue is?
You are not trying to reopen the window but you are creating a new window but pyqtleft only allows you to register a "map" object. So if you want to reopen the window after the user closed it then check that if the object exists then just use the show method:
def show_map(self):
if self.my_map is None:
# create map window instance
self.my_map = MapWindow()
else:
self.my_map.show()

How to display self defined QSplitter Class onto QMainWindow

I am currently trying to display a split screen view onto my window using PyQt5 with QSplitter and QMainWindow. I need QMainWindow to be able to create the menu options for the application that I am working on and would need to use QSplitter to use three separate windows for the application. Currently based on my code, the window is showing up, but there is no split screen shown at all. The only thing on the display is a blank screen when there should be the numbers: 1, 2, 3, and 4 shown in each corner.
I have tried to implement the QSplitters into the main window but then found that that approach does not work as it cannot set the layout of the QSplitters on top of setting the layout of the main window from QMainWindow. The next approach I used was the class based model where I defined what exactly I wanted for each splitter and implemented the subwindows into the main window and used two splitters (horizontal and vertical).
import sys
#imports
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QAction, QVBoxLayout, QStackedWidget
from PyQt5.QtWidgets import QMessageBox, QFrame, QSplitter, QTextEdit, QHBoxLayout, QLineEdit, QLabel
from PyQt5.QtGui import QKeySequence
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon #to import icon
'''
class widget1(QWidget):
"""docstring for widget1"""
def __init__(self):
QWidget.__init__(self)
hbox = QHBoxLayout()
#create split screen
#this is the top left frame of the window
topleft = QFrame()
topleft.setFrameShape(QFrame.StyledPanel)
#first splitter
splitter1 = QSplitter(Qt.Horizontal)
lineedit = QLineEdit()
splitter1.addWidget(topleft)
splitter1.addWidget(lineedit)
splitter1.setSizes([200,200])
#second splitter and it is located at the bottom of the screen
bottom = QFrame()
bottom.setFrameShape(QFrame.StyledPanel)
splitter2 = QSplitter(Qt.Horizontal)
#add the splitter to the layout
hbox.addWidget(splitter2)
'''
class SubWindow(QWidget):
def __init__(self, label):
super(SubWindow, self).__init__()
self.label = QLabel(label)
self.label.setAlignment(Qt.AlignCenter)
self.label.setStyleSheet("QLabel {font-size:40px;}")
self.main_layout = QVBoxLayout()
self.main_layout.addWidget(self.label)
self.setLayout(self.main_layout)
#GUI class to create window
class GUI(QMainWindow):
"""docstring for GUI"""
def __init__(self,):
# Understand and explain ...
super().__init__()
#initialize the UI using the initUI method
self.initUI()
def initUI(self):
#set the title of the window
self.setWindowTitle('Visualization')
#Set the status bar in the beginning
self.statusBar().showMessage("In Progress")
#create new menubar object at top of window
menubar = self.menuBar()
#add file button to menubar
file_menu = menubar.addMenu("File")
#add edit button to menubar
edit_menu = menubar.addMenu("Edit")
#add view button to menubar
view_menu = menubar.addMenu("View")
#path for new icon and create the icon
new_icon = QIcon('newfileicon.png')
open_icon =QIcon('openfileicon.png')
exitapp_icon = QIcon('exitappicon.png')
#create new subbutton for the file menu and add icon and shortcuts
#as well as connecting the methods for each file menu
new_action = QAction(new_icon,'New', self)
new_action.setShortcut('Ctrl+N')
new_action.triggered.connect(self.newCall)
open_action = QAction(open_icon,'Open', self)
open_action.setShortcut('Ctrl+O')
open_action.triggered.connect(self.openCall)
exit_action = QAction(exitapp_icon,'Exit', self)
exit_action.setShortcut('Ctrl+X')
exit_action.triggered.connect(self.exitCall)
#add the action to the file menu button
file_menu.addAction(new_action)
file_menu.addAction(open_action)
file_menu.addAction(exit_action)
#when hovering over the "new", "open", and "exit", update statusbar
new_action.setStatusTip("Create New File")
open_action.setStatusTip("Open a file")
exit_action.setStatusTip("Exit application")
#when clicking the exit, close the application
exit_action.triggered.connect(self.close)
self.SubWindow1 = SubWindow("1")
self.SubWindow2 = SubWindow("2")
self.SubWindow3 = SubWindow("3")
self.SubWindow4 = SubWindow("4")
self.subsplitter1 = QSplitter(Qt.Horizontal)
self.subsplitter1.addWidget(self.SubWindow1)
self.subsplitter1.addWidget(self.SubWindow2)
self.subsplitter2 = QSplitter(Qt.Horizontal)
self.subsplitter2.addWidget(self.SubWindow3)
self.subsplitter2.addWidget(self.SubWindow4)
self.subsplitter = QSplitter(Qt.Vertical)
self.subsplitter.addWidget(self.subsplitter1)
self.subsplitter.addWidget(self.subsplitter2)
self.main_layout = QVBoxLayout()
self.main_layout.addWidget(self.subsplitter)
self.setLayout(self.main_layout)
#hbox = widget1()
#self.view = QHBoxLayout(self)
#resize the window to a 900x800 window
self.resize(900, 800)
def newCall(self):
QMessageBox.about(self, "Confirmation", "Are you sure you want to create a new file?")
def openCall(self):
QMessageBox.about(self, "Confirmation", "Are you sure you want to open a file?")
#if yes to the messagebox, then close, else dont close and pass
def exitCall(self):
reply = QMessageBox.question(self, "Confirmation", "Are you sure you want to exit the application?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
self.close
sys.exit()
else:
pass
#main function
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = GUI()
gui.show()
sys.exit(app.exec_())
I expected there to be the results of having four split screens with the values of "1", "2", "3", and "4" on each corner of the screen. Instead the output is what I have gotten before which is just a blank screen with the menubar and status bar being functional.
QMainWindow unlike QWidget already has a predefined layout:
So you should not use a layout to set the QSplitter but use the setCentralWidget() method of QMainWindow:
# ...
self.subsplitter = QSplitter(Qt.Vertical)
self.subsplitter.addWidget(self.subsplitter1)
self.subsplitter.addWidget(self.subsplitter2)
self.setCentralWidget(self.subsplitter)
self.resize(900, 800)
# ...

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