QScroll area within QStackedLayout - python

I have a QMainWindow with a QStackedWidget as the central widget, and having been switching between layouts by changing the current widget of this central widget.
This has been working fine, but now I am trying to make one of these possible layouts scrollable and this is the result:
Code for MainWindow class:
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.central_widget = QtGui.QStackedWidget()
self.setCentralWidget(self.central_widget)
#-- On load open main menu
self.showMenu()
# Go to the menu screen
def showMenu(self):
widget_menu = WidgetMain(self)
widget_menu.btnConfigu.clicked.connect(self.showConfig)
self.central_widget.addWidget(widget_menu)
self.central_widget.setCurrentWidget(widget_menu)
self.resize(420,350)
# Go to the config screen
def showConfigu(self):
widget_configu = WidgetOptions(self)
self.central_widget.addWidget(widget_configu)
self.central_widget.setCurrentWidget(widget_configu)
Code for WidgetOptions class:
class WidgetOptions(QtGui.QWidget):
def __init__(self, parent=None):
super(WidgetOptions, self).__init__(parent)
#Container Widget
widget = QtGui.QWidget()
layoutRightContainer = QtGui.QVBoxLayout()
for _ in range(11):
btn = QtGui.QPushButton("test")
layoutRightContainer.addWidget(btn)
widget.setLayout(layoutRightContainer)
widget
self.setFixedHeight(300)
#Scroll Area Properties
scroll = QtGui.QScrollArea()
scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
scroll.setWidgetResizable(True)
scroll.setWidget(widget)
layoutMain = QtGui.QHBoxLayout()
layoutMain.addWidget(widget)
I've tried numerous tweaks to the set sizes, and making different containers non-/resizable. What works outside of a StackedWidget doesn't seem to work within one. There also doesn't seem to be any questions on SO with such a situation.
self.setLayout(layoutMain)

I solved this by making the WidgetOptions class itself an extension of QScrollArea rather than a QWidget containing the QScrollArea
Code for WidgetOptions class:
class WidgetOptions(QtGui.QScrollArea):
def __init__(self, parent=None):
super(WidgetOptions, self).__init__(parent)
layoutLeft = QtGui.QVBoxLayout()
self.btnVariables = QtGui.QPushButton("Variables")
self.btnGroups = QtGui.QPushButton("Groups")
layoutLeft.addWidget(self.btnVariables)
layoutLeft.addWidget(self.btnGroups)
#Container Widget
widget = QtGui.QWidget()
layoutRightContainer = QtGui.QVBoxLayout()
for _ in range(11):
btn = QtGui.QPushButton("test")
layoutRightContainer.addWidget(btn)
widget.setLayout(layoutRightContainer)
#Scroll Area Properties
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setWidgetResizable(True)
self.setWidget(widget)
self.setWidget(widget)

Related

How to add PyQt5 layout to parent window and show? [duplicate]

I am making a GUI with PyQt, and I am having issues with my MainWindow class. The window doesn't show widgets that I define in other classes, or it will show a small portion of the widgets in the top left corner, then cut off the rest of the widget.
Can someone please help me with this issue?
Here is some example code showing my issue.
import sys
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.resize(300, 400)
self.centralWidget = QtGui.QWidget(self)
self.hbox = QtGui.QHBoxLayout(self.centralWidget)
self.setLayout(self.hbox)
names = ['button1', 'button2', 'button3']
testButtons = buttonFactory(names, parent=self)
self.hbox.addWidget(testButtons)
class buttonFactory(QtGui.QWidget):
def __init__(self, names, parent=None):
super(buttonFactory, self).__init__(parent=parent)
self.vbox = QtGui.QVBoxLayout()
self.setLayout(self.vbox)
for name in names:
btn = QtGui.QPushButton(name)
self.vbox.addWidget(btn)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
gui = MainWindow()
gui.show()
app.exec_()
A QMainWindow has a central widget that is a container in which you should add your widgets. It has its own layout. The layout of the QMainWindow is for toolbars and such. The centralWidget must be set with the setCentralWidget method. It isn't enough to just call it self.centralWidget
Use the following three lines instead.
self.setCentralWidget(QtGui.QWidget(self))
self.hbox = QtGui.QHBoxLayout()
self.centralWidget().setLayout(self.hbox)

QLineEdit setCornerWidget width

I'm adding a QLineEdit to the menu bar with setCornerWidget. However, when setting a size with either setFixedWidth or setMinimumWidth, the QLineEdit is clipping through the window:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
menu = self.menuBar()
search = QLineEdit(self)
search.setFixedWidth(200)
menu.setCornerWidget(search)
It seems to be a bug, a workaround is to use a QWidget as a container:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
menu = self.menuBar()
search = QLineEdit()
search.setFixedWidth(200)
container = QWidget()
layout = QVBoxLayout(container)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(search)
menu.setCornerWidget(container)

Multiple QGraphicsViews and QGraphicsScenes in a MainWindow

I am looking to develop a Qt application whose main/parent widget is capable of 'holding' one or more "special" widgets. Each special widget displays a separate QGraphicsView and QGraphicsScene.
As far as I can see there can only be one central widget to which a graphics view can be set i.e. QMainWindow::setCentralWidget( QGraphicsView ), whereas I would like to have multiple graphics views.
Here is my failed quick and dirty attempt (in PySide)
#!/usr/bin/python
from PySide import QtGui
import sys
class MyApp(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
layout = QtGui.QHBoxLayout()
self.scene1 = QtGui.QGraphicsScene(self)
self.scene1.addRect(5,5,200,200)
self.view1 = QtGui.QGraphicsView(self.scene1, self)
self.scene2 = QtGui.QGraphicsScene(self)
self.scene2.addLine(500,500,300,300)
self.view2 = QtGui.QGraphicsView(self.scene1, self)
layout.addWidget(self.view1)
layout.addWidget(self.view2)
self.setLayout(layout)
self.show()
if __name__=="__main__":
app=QtGui.QApplication(sys.argv)
myapp = MyApp()
sys.exit(app.exec_())
QMainWindow has a default layout, you do not have to set it. In Qt a QWidget can be used as a container, so we create a widget that will be the container of the QGraphicsViews and also the centralwidget:
class MyApp(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyApp, self).__init__(parent)
self.scene1 = QtGui.QGraphicsScene(self)
self.scene1.addRect(5,5,200,200)
self.view1 = QtGui.QGraphicsView(self.scene1)
self.scene2 = QtGui.QGraphicsScene(self)
self.scene2.addLine(500,500,300,300)
self.view2 = QtGui.QGraphicsView(self.scene2)
central_widget = QtGui.QWidget()
layout = QtGui.QHBoxLayout(central_widget)
layout.addWidget(self.view1)
layout.addWidget(self.view2)
self.setCentralWidget(central_widget)
self.show()

PyQt Options for each Tab Widget

I have a tab widget that contains table widgets for each tab, and I also have a dock widget with options. One of the options is the column count, and I want to change it as soon as the column count spin box value changes. But when switching to a different tab, I'd like the spin box value (and all other options) to reset / switch to that specific tab's settings.
My question is how to best do this and still have the options as a dock widget. I could store all settings as variables for each tab widget and then change the value each time a new tab is opened, I guess, but maybe there is a better solution.
from PyQt5 import QtWidgets, QtCore
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__()
self.__setup__()
def __setup__(self):
self.resize(400, 400)
tabWidget = TabWidget(self)
self.setCentralWidget(tabWidget)
options = Options(self)
optionsDock = QtWidgets.QDockWidget()
optionsDock.setWidget(options)
optionsDock.setWindowTitle("Options")
self.addDockWidget(QtCore.Qt.TopDockWidgetArea, optionsDock)
options.spinBox_columns.valueChanged.connect(lambda: tabWidget.tabWidget.currentWidget().
setColumnCount(options.spinBox_columns.value()))
class Options(QtWidgets.QWidget):
def __init__(self, parent):
super(Options, self).__init__(parent)
self.__setup__()
def __setup__(self):
self.spinBox_columns = QtWidgets.QSpinBox()
self.spinBox_columns.setValue(1)
self.spinBox_columns.setMinimum(1)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.spinBox_columns)
self.setLayout(layout)
class TabWidget(QtWidgets.QWidget):
def __init__(self, parent):
super(TabWidget, self).__init__(parent)
self.__setup__()
def __setup__(self):
self.tabWidget = QtWidgets.QTabWidget()
for i in range(3):
widget = QtWidgets.QTableWidget()
widget.setColumnCount(1)
widget.setRowCount(3)
self.tabWidget.addTab(widget, "Column " + str(i))
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tabWidget)
self.setLayout(layout)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
You have to connect the currentChanged signal provided by the index of the tab, then use the widget() method to obtain the index associated with that index, then access its QTabWidget and obtain the number of columns using it to place the value to the QSpinBox.
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.__setup__()
def __setup__(self):
self.resize(400, 400)
tabWidget = TabWidget(self)
self.setCentralWidget(tabWidget)
options = Options(self)
optionsDock = QtWidgets.QDockWidget()
optionsDock.setWidget(options)
optionsDock.setWindowTitle("Options")
self.addDockWidget(QtCore.Qt.TopDockWidgetArea, optionsDock)
tabWidget.tabWidget.currentChanged.connect(lambda index: options.spinBox_columns.
setValue(tabWidget.tabWidget.widget(index).columnCount()))
options.spinBox_columns.valueChanged.connect(lambda value: tabWidget.tabWidget.currentWidget().
setColumnCount(value))

Widget on corner QTabBar is not in corner

I have a pushbutton to add a tab in a QTabWidget. But when I change the button's size, it's not in the corner anymore. So how can I bring it to the corner like in the first picture?
Not change size:
Change size:
Here is my code:
from PyQt4 import QtGui, QtCore
class PlaylistTable(QtGui.QWidget):
def __init__(self):
super(PlaylistTable, self).__init__()
self.playlistTable = QtGui.QTableWidget(self)
self.playlistTable.setFrameShape(QtGui.QFrame.NoFrame)
self.playlistTable.setFrameShadow(QtGui.QFrame.Sunken)
self.playlistTable.setLineWidth(0)
self.playlistTable.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.playlistTable.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.playlistTable.setHorizontalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.playlistTable.setShowGrid(True)
self.playlistTable.setGridStyle(QtCore.Qt.SolidLine)
self.playlistTable.setWordWrap(True)
self.playlistTable.setCornerButtonEnabled(True)
self.playlistTable.verticalHeader().setVisible(False)
class CustomTabWidget(QtGui.QTabWidget):
"""Tab Widget that that can have new tabs easily added to it."""
def __init__(self, parent=None):
super(CustomTabWidget, self).__init__(parent)
# QtGui.QTabWidget.__init__(self, parent)
# Tab Bar
self.tab = QtGui.QTabBar()
self.setTabBar(self.tab)
# Properties
self.setMovable(True)
self.setTabsClosable(True)
self.plusButton = QtGui.QPushButton("+")
self.plusButton.setFixedSize(QtCore.QSize(22, 22))
self.setCornerWidget(self.plusButton)
# Signals
self.connect(self.plusButton, QtCore.SIGNAL('clicked()'), self.addTab)
# self.tab.plusClicked.connect(self.addTab)
self.tab.tabMoved.connect(self.tab.moveTab)
self.tabCloseRequested.connect(self.removeTab)
def addTab(self):
string = QtCore.QString.fromUtf8("Playlist")
tab = PlaylistTable()
super(CustomTabWidget, self).addTab(tab, string)
class AppDemo(QtGui.QMainWindow):
def __init__(self):
super(AppDemo, self).__init__()
self.centralwidget = QtGui.QWidget(self)
self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setContentsMargins(0, -1, 0, -1)
self.playlist_manager = CustomTabWidget(self.centralwidget)
self.horizontalLayout.addWidget(self.playlist_manager)
self.playlist_manager.addTab()
self.setCentralWidget(self.centralwidget)
self.show()
# end class AppDemo
def main():
import sys
app = QtGui.QApplication(sys.argv)
w = AppDemo()
w.setWindowTitle('AppDemo')
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I'm guessing the reason is this, from QTabWidget Documentation:
The geometry of the widget is determined
based on the widget's sizeHint() and the style().
If you print the sizeHint() of the QPushButton you will see that width never goes below a certain value.
I've found an alternative is to use a QToolButton which can do everything (even more) a QPushButton does.
self.plusButton = QtGui.QToolButton(self)
self.plusButton.setText("+")

Categories