I want to uncheck some radio buttons in class A by pushing a button in class B.
My example codes are as below:
import sys, os
import PyQt4
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Widget1(QWidget):
def __init__(self, bridge, parent=None):
super().__init__()
self.bridge = bridge
self.grid = QGridLayout()
self.radiobtn = QRadioButton()
self.grid.addWidget(self.radiobtn, 0, 0)
class Widget2(QWidget):
def __init__(self, parent = None):
super().__init__()
self.grid = QGridLayout()
self.pushbtn = QPushButton()
self.grid.addWidget(self.pushbtn,0, 0)
class Tab1Layout(QWidget):
def __init__(self, parent = None):
super().__init__()
self.grid = QGridLayout()
self.group2 = Widget2()
self.group1 = Widget1(self.group2, self)
self.grid.addWidget(self.group1, 0, 0)
self.grid.addWidget(self.group2, 1, 0)
class Tabs(QTabWidget):
def __init__(self, parent = None):
super().__init__()
self.tab1 = Tab1Layout()
self.addTab(self.tab1, 'Tab1')
self.show()
def main():
app = QApplication(sys.argv)
main = Tabs()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
As my code is now, it has two problems:
The radio button and the push button don't show up
Let's say the radio button and the push button finally show up: I want that when I click the push button in Widget2, the radio button in Widget1 should be unchecked if it is already checked.
Please note that I'm already linking Widget1 and Widget2 by putting a second argument bridge in Widget1. The reason I did this is because there's some other functions in my original project. So please don't alter this part if possible.
The buttons don't show up because you have not added the grid layouts to any of the widgets. So for all three grid layouts, do either this:
self.grid = QGridLayout()
self.setLayout(self.grid)
or this:
self.grid = QGridLayout(self)
To check/uncheck the radio button using a button click, do this:
class Tab1Layout(QWidget):
def __init__(self, parent = None):
...
self.group2.pushbtn.clicked.connect(self.group1.radiobtn.toggle)
Related
I want to make GUI like below with PyQt5, but I can't find an example to help me.
I searched for "change layout on qwidget" and "tab pane with no title bar" and "card layout" without luck. How can I make this with PyQt5?
You have to use a QStackedLayout (or a QStackedWidget) that changes pages when the buttons are pressed. And the first page should have the buttons. I have also implemented the back() method that returns to the initial page, that slot must be invoked when the Change button is pressed:
from functools import partial
from PyQt5 import QtCore, QtWidgets
class CardWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(CardWidget, self).__init__(parent)
self._layout = QtWidgets.QStackedLayout(self)
button_widget = QtWidgets.QWidget()
self.btn_lay = QtWidgets.QFormLayout(button_widget)
self._layout.addWidget(button_widget)
def add_widget(self, text, widget):
self._layout.addWidget(widget)
btn = QtWidgets.QPushButton(text)
self.btn_lay.addRow(btn)
btn.clicked.connect(partial(self._layout.setCurrentWidget, widget))
#QtCore.pyqtSlot()
def back(self):
self._layout.setCurrentIndex(0)
class Widget(QtWidgets.QWidget):
backSignal = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.le1 = QtWidgets.QLineEdit()
self.le2 = QtWidgets.QLineEdit()
button = QtWidgets.QPushButton("Change")
button.clicked.connect(self.backSignal)
flay = QtWidgets.QFormLayout()
flay.addRow("Value 1:", self.le1)
flay.addRow("Value 2:", self.le2)
lay = QtWidgets.QVBoxLayout(self)
lay.addLayout(flay)
lay.addWidget(button)
def create_label():
label = QtWidgets.QLabel(
"Some Other Components",
alignment=QtCore.Qt.AlignCenter
)
label.setStyleSheet("background-color:blue;")
return label
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
c = CardWidget()
for i in range(3):
w = Widget()
w.backSignal.connect(c.back)
c.add_widget("Want to Change value {}".format(i+1), w)
p = QtWidgets.QWidget()
lay = QtWidgets.QGridLayout(p)
lay.addWidget(create_label(), 0, 0, 1, 2)
lay.addWidget(c, 1, 0)
lay.addWidget(create_label(), 1, 1)
lay.setColumnStretch(0, 1)
lay.setColumnStretch(1, 1)
lay.setRowStretch(0, 1)
lay.setRowStretch(1, 1)
p.resize(640, 480)
p.show()
sys.exit(app.exec_())
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))
By clicking a button, I want to print some texts that is entered in QLineEdit when a checkbox is checked. My example codes are as below:
import sys
import PyQt4
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Widget(QWidget):
def __init__(self, parent= None):
super(Widget, self).__init__(parent)
layout = QGridLayout()
self.setLayout(layout)
self.checkBox = QCheckBox()
layout.addWidget(self.checkBox, 0, 0)
self.le = QLineEdit()
layout.addWidget(self.le, 0, 1)
self.btn = QPushButton('Run')
layout.addWidget(self.btn, 0, 3)
class Func ():
def __init__(self):
a = Widget(self)
def someFunc(self):
##print ()
app = QApplication(sys.argv)
widget = Widget()
widget.show()
app.exec_()
As you can see above, I want the button in "Widget" class to connect to "someFunc" method in "Func" class. Thus when some texts are entered in "self.le" as well as "checkBox" is checked, I want "someFunc" to print the texts entered in "self.le" by clicking the button. If the "checkbox" is not checked, clicking the button should not cause anything to happen even when some texts are entered.
If anyone knows how to solve it, pls let me know thanks!!
You need to connect the button's clicked signal to the function that will handle it. Like this: button.clicked.connect(handler_function)
import sys
import PyQt5
from PyQt5.QtWidgets import *
class Func ():
def __init__(self, widget):
self.w = widget
def someFunc(self):
if self.w.checkBox.isChecked():
print(self.w.le.text())
class Widget(QWidget):
def __init__(self, parent= None):
super(Widget, self).__init__(parent)
layout = QGridLayout()
self.setLayout(layout)
self.checkBox = QCheckBox()
layout.addWidget(self.checkBox, 0, 0)
self.le = QLineEdit()
layout.addWidget(self.le, 0, 1)
self.btn = QPushButton('Run')
layout.addWidget(self.btn, 0, 3)
# connecting to a method in this class
# self.btn.clicked.connect(self.some_func)
#connecting to a method in another class
self.handler_class = Func(self)
self.btn.clicked.connect(self.handler_class.someFunc)
def some_func(self):
if self.checkBox.isChecked():
print(self.le.text())
app = QApplication(sys.argv)
widget = Widget()
widget.show()
app.exec_()
Edit:
Put simply: In the Func class self.w contains a reference to the widget from which a signal will be emitted when the button is clicked.
Why am I keeping a reference to that widget? So that I can access the widget's combobox and lineedit. Without a way to access them I can't see if the checkbox is checked or what the user typed in the textedit.
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)
i'd like to learn PyQt by writing a simple game. the first widget would have buttons like "New game", "Quit", etc. i am having trouble understanding how to transition from that menu widget to a new one.
for instance, if i were to click New Game, how do i have a new widget appear that replaces the old one and asks for the user's name? the way i am approaching it now is something like
Form = QtGui.QWidget()
ui = uiMainMenu()
ui.setupUi(Form)
Form.show()
then once newGameButton is pressed it would go to a subroutine...
Form2 = QtGui.QWidget()
ui2 = uiNewGame()
ui2.setupUi(Form2)
Form2.show()
i'm not asking for all the code, just an explanation as to how i should be approaching the problem, because the code above ain't doing squat.
thanks!
if you want to switch between forms then you can use QStackedWidget.
Below you can find a working sample code:
import sys
from functools import partial
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Form1(QWidget):
showForm2Signal = pyqtSignal()
def __init__(self, parent=None):
super(Form1, self).__init__(parent)
self.newGameButton = QPushButton("New Game", self)
self.quitButton = QPushButton("Quit", self)
layout = QVBoxLayout(self)
layout.addWidget(QLabel("<html>My Game<br>Start Page</html>"))
layout.addWidget(self.newGameButton)
layout.addWidget(self.quitButton)
self.newGameButton.clicked.connect(self.showForm2Signal.emit)
self.quitButton.clicked.connect(qApp.quit)
class Form2(QWidget):
showForm1Signal = pyqtSignal()
def __init__(self, parent=None):
super(Form2, self).__init__(parent)
self.backButton = QPushButton("Back", self)
layout = QVBoxLayout(self)
layout.addWidget(QLabel("New Game Started!"))
layout.addWidget(self.backButton)
self.backButton.clicked.connect(self.showForm1Signal.emit)
class MainWidget(QWidget):
def __init__(self, parent=None):
super(MainWidget, self).__init__(parent)
self.stack = QStackedWidget()
layout = QVBoxLayout(self)
layout.addWidget(self.stack)
self.form1 = Form1(self)
self.form2 = Form2(self)
self.stack.addWidget(self.form1)
self.stack.addWidget(self.form2)
self.form1.showForm2Signal.connect(partial(self.stack.setCurrentWidget,
self.form2))
self.form2.showForm1Signal.connect(partial(self.stack.setCurrentWidget,
self.form1))
self.stack.setCurrentWidget(self.form1)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWidget()
w.show()
app.exec_()
sys.exit()
If you only want to ask the name to the user then you can use a QDialog widget.