How to add a tab in PySide - python

I am trying to add tab for 2 grid layout, but when I ran the code it seems like there is no tab.
I think
wid_inner.tab = QtGui.QTabWidget()
is not adding the tab correctly to the grid
import sys
from PySide import QtGui
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
# setting the outter widget and layout
wid = QtGui.QWidget()
grid = QtGui.QGridLayout()
wid.setLayout(grid)
# setting the inner widget and layout
grid_inner = QtGui.QGridLayout()
wid_inner = QtGui.QWidget()
wid_inner.setLayout(grid_inner)
# add the inner widget to the outer layout
grid.addWidget(wid_inner)
# add tab frame to widget
wid_inner.tab = QtGui.QTabWidget()
# create tab
new_tab = QtGui.QWidget()
grid_tab = QtGui.QGridLayout()
grid_tab.setSpacing(10)
new_tab.setLayout(grid_tab)
new_tab.tab_name_private = "test1"
wid_inner.tab.addTab(new_tab, "test1")
# create tab 2
new_tab2 = QtGui.QWidget()
new_tab2.setLayout(grid_tab)
wid_inner.tab.addTab(new_tab2, "test2")
wid.show()
sys.exit(app.exec_())
Any help would be appreciated thanks

You need to provide the parent to each inner widget, and the tab widget wid_inner.tab was not being added to any layout. This seems a little complicated to establish the layout... Have you considered using QtDesigner?
wid = QtGui.QWidget()
grid = QtGui.QGridLayout(wid)
wid.setLayout(grid)
# setting the inner widget and layout
grid_inner = QtGui.QGridLayout(wid)
wid_inner = QtGui.QWidget(wid)
wid_inner.setLayout(grid_inner)
# add the inner widget to the outer layout
grid.addWidget(wid_inner)
# add tab frame to widget
wid_inner.tab = QtGui.QTabWidget(wid_inner)
grid_inner.addWidget(wid_inner.tab)
# create tab
new_tab = QtGui.QWidget(wid_inner.tab)
grid_tab = QtGui.QGridLayout(new_tab)
grid_tab.setSpacing(10)
new_tab.setLayout(grid_tab)
new_tab.tab_name_private = "test1"
wid_inner.tab.addTab(new_tab, "test1")
# create tab 2
new_tab2 = QtGui.QWidget(wid_inner.tab)
new_tab2.setLayout(grid_tab)
wid_inner.tab.addTab(new_tab2, "test2")
wid.show()
app.exec_()

Related

Change in PyQt QDialog Layout Does Not Update Correctly -- bug or my error? [duplicate]

I have a QVBox layout that houses a QVBox layout and a QHBox layout. I use the other QVBox layout to hold dynamically created GUI objects and the QHBox layout to hold the buttons that add/remove those objects. Everything works correctly if I position the QHBox on top of the QVBox, but when I try to position the QHBox beneath the QVBox the objects aren't removed correctly but stay there "lingering" on top of the QHBox. I'll upload pictures to demonstrate the problem. First picture is before taking action, second is after creating a new object and third is after deleting the object
Here is the code that creates and deletes the new objects
def addClient(self):
if (len(self.clients) < 5):
client = clientComponent(self)
self.clients.append(client)
index = len(self.clients)-1
self.vLayout3.addWidget(self.clients[index])
client.setIndex(index)
self.clients[index].startButton.clicked.connect(partial(self.threadcontrol, '2', client.getIndex()))
self.clients[index].stopButton.clicked.connect(partial(self.clientstop, '0', client.getIndex()))
def deleteClient(self):
if (len(self.clients) > 1):
self.vLayout3.removeWidget(self.clients.pop())
This is where I complete the layout
def initializeUi(self):
self.mainWidget = QWidget(self)
self.setCentralWidget(self.mainWidget)
self.mainLayout = QVBoxLayout(self.mainWidget)
self.hLayout1 = QHBoxLayout()
self.hLayout2 = QHBoxLayout()
self.vLayout1 = QVBoxLayout()
self.vLayout2 = QVBoxLayout()
self.vLayout3 = QVBoxLayout()
self.addServer()
self.addClient()
self.serverBox = QGroupBox('Server')
self.clientBox = QGroupBox('Client')
self.traffic1 = QLabel('0.0Mb/s', self)
self.traffic1.setAlignment(Qt.AlignRight)
self.traffic2 = QLabel('0.0Mb/s', self)
self.traffic2.setAlignment(Qt.AlignCenter)
self.traffic3 = QLabel('0.0Mb/s', self)
self.traffic3.setAlignment(Qt.AlignLeft)
self.newClientButton = QPushButton('+', self)
self.deleteClientButton = QPushButton('-', self)
self.hLayout1.addWidget(self.traffic1)
self.hLayout1.addWidget(self.traffic2)
self.hLayout1.addWidget(self.traffic3)
self.hLayout2.addWidget(self.newClientButton)
self.hLayout2.addWidget(self.deleteClientButton)
self.vLayout2.addLayout(self.vLayout3)
self.vLayout2.addLayout(self.hLayout2)
self.mainLayout.addWidget(self.plot)
self.mainLayout.addLayout(self.hLayout1)
self.serverBox.setLayout(self.vLayout1)
self.mainLayout.addWidget(self.serverBox)
self.clientBox.setLayout(self.vLayout2)
self.mainLayout.addWidget(self.clientBox)
This is happening because your main window remains the parent of the client widgets after you remove them from the layout. You will see similar behaviour if you assign a widget a parent widget without adding it to any layout.
Removing the parent should resolve the issue.
def deleteClient(self):
if (len(self.clients) > 1):
client = self.clients.pop()
self.vLayout3.removeWidget(client)
client.setParent(None)
You may also need to make a call to adjustSize to resize the window to fit the remaining widgets
When you delete a widget from layout it still remains in parent widget's
object tree, so it gets displayed outside of any layout.
To remove a widget from the object tree call widget.setParent(None).
widget.deleteLater() also works.
Here is my MCVE(Qt4, Py2.7):
from PyQt4.QtGui import (QApplication, QWidget, QPushButton,
QVBoxLayout, QHBoxLayout)
app=QApplication([])
self = QWidget()
main_layout = QVBoxLayout(self)
clients = []
l2 = QHBoxLayout()
main_layout.addLayout(l2)
b_add = QPushButton('add', self)
l2.addWidget(b_add)
def addClient():
b = QPushButton(str(len(clients)), self)
clients.append(b)
main_layout.addWidget(b)
b_add.clicked.connect(addClient)
b_rm = QPushButton('rm', self)
l2.addWidget(b_rm)
def deleteClient():
b = clients.pop()
main_layout.removeWidget(b)
# comment out two following lines to get the behavior you observe
b.setParent(None)
self.adjustSize()
b_rm.clicked.connect(deleteClient)
self.show()
app.exec_()
On my system I also have to call self.adjustSize() after deletion to resize the main window

PyQt5 adding add and remove widget buttons beside every tab

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_())

How to force a layout to resize with the wizard page

I have a wizard page that displays two tables and a hand full of buttons. Part of my tables scroll bars and the bottom buttons keep getting hidden and I have to expand the window when that page is reached. I am not sure if the overall layout scheme I have for this page is just set up improperly.
How can I have the layout and widgets within the layout resize along with the window?
I am using PySide2 on Python 3.7. I have tried setting the layout as a fixed size along with reading a few other threads on this but I can't seem to reproduce the same results so that the widgets fit within the window/as the window resize they scale with it.
class Resolution_Page(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super(Resolution_Page, self).__init__(parent)
self.Resolution_Wizard_Page = QtWidgets.QWizardPage()
self.Resolution_Wizard_Page.setObjectName("Resolution_Wizard_Page")
self.ResolutionTable = QtWidgets.QTableWidget()
self.ResolutionTable.setObjectName('ResolutionTable')
self.SearchTable = QtWidgets.QTableWidget()
self.SearchTable.setObjectName('SearchTable')
self.SearchTable.setColumnCount(2)
self.SearchTable.setHorizontalHeaderLabels(['Searched Field', 'Searched Value'])
self.SearchTable.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
self.SearchTable.setSortingEnabled(False)
self.SearchTable.setEnabled(True)
self.SearchTable.setRowCount(0)
self.next_resolution_button = QtWidgets.QPushButton('Next Resolution')
self.next_resolution_button.setObjectName('next_resolution_button')
self.next_resolution_button.setMaximumWidth(200)
self.next_search_button = QtWidgets.QPushButton('Next Page')
self.next_search_button.setObjectName('next_search_button')
self.resolve_button = QtWidgets.QPushButton('Resolve Selection')
self.resolve_button.setEnabled(False)
self.resolve_button.setObjectName('resolve_button')
self.Search = QtWidgets.QPushButton('Search')
self.Search.setObjectName('Search')
self.previous_search_result_button = QtWidgets.QPushButton('Previous Page')
self.previous_search_result_button.setObjectName('previous_search_result_button')
self.previous_resolution_button = QtWidgets.QPushButton('Previous Resolution')
self.previous_resolution_button.setObjectName('previous_resolution_button')
self.previous_resolution_button.setMaximumWidth(200)
self.SearchTable.setMinimumWidth(300)
layout = QtWidgets.QWidget(self)
root_layout = QtWidgets.QVBoxLayout(layout)
central_tables = QtWidgets.QHBoxLayout()
middle_buttons = QtWidgets.QVBoxLayout()
bottom_buttons = QtWidgets.QHBoxLayout()
middle_buttons.addWidget(self.previous_search_result_button)
middle_buttons.addWidget(self.Search)
middle_buttons.addWidget(self.next_search_button)
central_tables.addWidget(self.SearchTable, stretch=1)
central_tables.addLayout(middle_buttons)
central_tables.addWidget(self.ResolutionTable, stretch=1)
bottom_buttons.addWidget(self.previous_resolution_button)
bottom_buttons.addWidget(self.resolve_button)
bottom_buttons.addWidget(self.next_resolution_button)
bottom_buttons.setAlignment(QtCore.Qt.AlignBottom)
root_layout.addLayout(central_tables)
root_layout.addLayout(bottom_buttons)
layout.setFixedSize(1200,600)
You should parent your top widget to a main layout and prevent using a fixed size for main widget
Create a main layout and parent your widget to it:
main_layout = QtWidgets.QVBoxLayout(self)
#layout = QtWidgets.QWidget(self)
layout = QtWidgets.QWidget()
main_layout.addWidget(layout)
remove this line:
layout.setFixedSize(1200,600)

Create Tabs which affect only particular area of the GUI

I would like to create tabs which target only a specific area within the GUI.
That is there should be an area of the GUI which is static and always present even when changing tab.
I have already created tabs as according to the following code:
import sys
from PyQt4 import QtGui
def main():
app = QtGui.QApplication(sys.argv)
tabs = QtGui.QTabWidget()
# Create tabs
tab1 = QtGui.QWidget()
tab2 = QtGui.QWidget()
tab3 = QtGui.QWidget()
tab4 = QtGui.QWidget()
# Resize width and height
tabs.resize(1000, 1000)
# Set layout of first tab
vBoxlayout = QtGui.QVBoxLayout()
pushButton1 = QtGui.QPushButton("Start")
pushButton2 = QtGui.QPushButton("Settings")
pushButton3 = QtGui.QPushButton("Stop")
vBoxlayout.addWidget(pushButton1)
vBoxlayout.addWidget(pushButton2)
vBoxlayout.addWidget(pushButton3)
tab1.setLayout(vBoxlayout)
# Add tabs
tabs.addTab(tab1,"Tab 1")
tabs.addTab(tab2,"Tab 2")
tabs.addTab(tab3,"Tab 3")
tabs.addTab(tab4,"Tab 4")
# Set title and show
tabs.setWindowTitle('PyQt QTabWidget # pythonspot.com')
tabs.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I think there is several solution to achieve this.
I will give an example.
First of all, you need to create a main window, where you will create a layout with 2 frames (I took gridlayout for this example). Once done, you can now set one layout per frame, and add widget as you want in those layout. It will populate the frame. So you can populate one frame with your tabs, and one which stay fix.
I did not take in consideration size of the widget, you can fit them as you want.
I just modified a little your example :
import sys
from PyQt4 import QtGui, QtCore
def main():
app = QtGui.QApplication(sys.argv)
mainWindow = QtGui.QWidget()
mainLayout = QtGui.QGridLayout(mainWindow)
frameLeft = QtGui.QFrame(mainWindow)
frameLeft.setFrameShape(QtGui.QFrame.StyledPanel)
frameLeft.setFrameShadow(QtGui.QFrame.Raised)
gridLayoutLeft = QtGui.QGridLayout(frameLeft)
mainLayout.addWidget(frameLeft, 0, 0, 1, 1, QtCore.Qt.AlignVCenter)
frameRigth = QtGui.QFrame(mainWindow)
frameRigth.setFrameShape(QtGui.QFrame.StyledPanel)
frameRigth.setFrameShadow(QtGui.QFrame.Raised)
gridLayoutRigth = QtGui.QGridLayout(frameRigth)
mainLayout.addWidget(frameRigth, 0, 1, 1, 1, QtCore.Qt.AlignVCenter)
tabs = QtGui.QTabWidget()
gridLayoutRigth.addWidget(tabs, 0, 0, 1, 1, QtCore.Qt.AlignVCenter)
button = QtGui.QPushButton('test')
gridLayoutLeft.addWidget(button, 0, 0, 1, 1, QtCore.Qt.AlignVCenter)
# Create tabs
tab1 = QtGui.QWidget()
tab2 = QtGui.QWidget()
tab3 = QtGui.QWidget()
tab4 = QtGui.QWidget()
# Set layout of first tab
vBoxlayout = QtGui.QVBoxLayout()
pushButton1 = QtGui.QPushButton("Start")
pushButton2 = QtGui.QPushButton("Settings")
pushButton3 = QtGui.QPushButton("Stop")
vBoxlayout.addWidget(pushButton1)
vBoxlayout.addWidget(pushButton2)
vBoxlayout.addWidget(pushButton3)
tab1.setLayout(vBoxlayout)
# Add tabs
tabs.addTab(tab1, "Tab 1")
tabs.addTab(tab2, "Tab 2")
tabs.addTab(tab3, "Tab 3")
tabs.addTab(tab4, "Tab 4")
# Set title and show
mainWindow.setWindowTitle('PyQt QTabWidget # pythonspot.com')
mainWindow.resize(mainWindow.sizeHint())
mainWindow.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I hope this help !

Pyqt widget lingers after being removed

I have a QVBox layout that houses a QVBox layout and a QHBox layout. I use the other QVBox layout to hold dynamically created GUI objects and the QHBox layout to hold the buttons that add/remove those objects. Everything works correctly if I position the QHBox on top of the QVBox, but when I try to position the QHBox beneath the QVBox the objects aren't removed correctly but stay there "lingering" on top of the QHBox. I'll upload pictures to demonstrate the problem. First picture is before taking action, second is after creating a new object and third is after deleting the object
Here is the code that creates and deletes the new objects
def addClient(self):
if (len(self.clients) < 5):
client = clientComponent(self)
self.clients.append(client)
index = len(self.clients)-1
self.vLayout3.addWidget(self.clients[index])
client.setIndex(index)
self.clients[index].startButton.clicked.connect(partial(self.threadcontrol, '2', client.getIndex()))
self.clients[index].stopButton.clicked.connect(partial(self.clientstop, '0', client.getIndex()))
def deleteClient(self):
if (len(self.clients) > 1):
self.vLayout3.removeWidget(self.clients.pop())
This is where I complete the layout
def initializeUi(self):
self.mainWidget = QWidget(self)
self.setCentralWidget(self.mainWidget)
self.mainLayout = QVBoxLayout(self.mainWidget)
self.hLayout1 = QHBoxLayout()
self.hLayout2 = QHBoxLayout()
self.vLayout1 = QVBoxLayout()
self.vLayout2 = QVBoxLayout()
self.vLayout3 = QVBoxLayout()
self.addServer()
self.addClient()
self.serverBox = QGroupBox('Server')
self.clientBox = QGroupBox('Client')
self.traffic1 = QLabel('0.0Mb/s', self)
self.traffic1.setAlignment(Qt.AlignRight)
self.traffic2 = QLabel('0.0Mb/s', self)
self.traffic2.setAlignment(Qt.AlignCenter)
self.traffic3 = QLabel('0.0Mb/s', self)
self.traffic3.setAlignment(Qt.AlignLeft)
self.newClientButton = QPushButton('+', self)
self.deleteClientButton = QPushButton('-', self)
self.hLayout1.addWidget(self.traffic1)
self.hLayout1.addWidget(self.traffic2)
self.hLayout1.addWidget(self.traffic3)
self.hLayout2.addWidget(self.newClientButton)
self.hLayout2.addWidget(self.deleteClientButton)
self.vLayout2.addLayout(self.vLayout3)
self.vLayout2.addLayout(self.hLayout2)
self.mainLayout.addWidget(self.plot)
self.mainLayout.addLayout(self.hLayout1)
self.serverBox.setLayout(self.vLayout1)
self.mainLayout.addWidget(self.serverBox)
self.clientBox.setLayout(self.vLayout2)
self.mainLayout.addWidget(self.clientBox)
This is happening because your main window remains the parent of the client widgets after you remove them from the layout. You will see similar behaviour if you assign a widget a parent widget without adding it to any layout.
Removing the parent should resolve the issue.
def deleteClient(self):
if (len(self.clients) > 1):
client = self.clients.pop()
self.vLayout3.removeWidget(client)
client.setParent(None)
You may also need to make a call to adjustSize to resize the window to fit the remaining widgets
When you delete a widget from layout it still remains in parent widget's
object tree, so it gets displayed outside of any layout.
To remove a widget from the object tree call widget.setParent(None).
widget.deleteLater() also works.
Here is my MCVE(Qt4, Py2.7):
from PyQt4.QtGui import (QApplication, QWidget, QPushButton,
QVBoxLayout, QHBoxLayout)
app=QApplication([])
self = QWidget()
main_layout = QVBoxLayout(self)
clients = []
l2 = QHBoxLayout()
main_layout.addLayout(l2)
b_add = QPushButton('add', self)
l2.addWidget(b_add)
def addClient():
b = QPushButton(str(len(clients)), self)
clients.append(b)
main_layout.addWidget(b)
b_add.clicked.connect(addClient)
b_rm = QPushButton('rm', self)
l2.addWidget(b_rm)
def deleteClient():
b = clients.pop()
main_layout.removeWidget(b)
# comment out two following lines to get the behavior you observe
b.setParent(None)
self.adjustSize()
b_rm.clicked.connect(deleteClient)
self.show()
app.exec_()
On my system I also have to call self.adjustSize() after deletion to resize the main window

Categories