Related
I'm trying to toggle on/off a button based on the value of control variables (choice1_is_selected & choice2_is_selected), which are defined as global.
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout, QHBoxLayout, QLabel, QComboBox, QPushButton
class duo(QWidget):
def __init__(self,text,choice):
super().__init__()
layoutC = QHBoxLayout()
layoutC.addWidget(QLabel(text))
options=QComboBox()
options.addItems(choice)
options.currentTextChanged.connect(self.text_changed)
layoutC.addWidget(options)
self.setLayout(layoutC)
def text_changed(self, s):
global choice1_is_selected,choice2_is_selected
choice1_is_selected = True
class duoB(QWidget):
def __init__(self,text,choice):
super().__init__()
layoutB = QHBoxLayout()
layoutB.addWidget(QLabel(text))
options=QComboBox()
options.addItems(choice)
options.currentTextChanged.connect(self.text_changed)
layoutB.addWidget(options)
self.setLayout(layoutB)
def text_changed(self, s):
global choice1_is_selected,choice2_is_selected
choice2_is_selected = True
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("Reproducible")
layout = QGridLayout()
layout.addWidget(QLabel("Block 1"),0,0)
text2 = 'Block 2'
select2 = ['Not selected','first','second']
widgetcomposite1 = duo(text2,select2)
layout.addWidget(widgetcomposite1,1,0)
text3 = 'Block 3'
select3 = ['Unselected','I','II']
widgetcomposite2 = duoB(text3,select3)
layout.addWidget(widgetcomposite2,2,0)
self.btn_download = QPushButton('Download')
if (choice1_is_selected == True) and (choice2_is_selected == True):
self.btn_download.setDisabled(False)
else:
self.btn_download.setDisabled(True)
layout.addWidget(self.btn_download,3,0)
self.setLayout(layout)
app = QApplication(sys.argv)
choice1_is_selected = False
choice2_is_selected = False
window = MainWindow()
window.show()
app.exec()
What is tripping me is that the code seems to check the conditional statement at the start but not later so it never enables the download option.
It doesn't work because your if statement no longer works after execution.
You should call that statement again (using signals, calling the function, etc.).
Here is a possible solution that worked for me:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout, QHBoxLayout, QLabel, QComboBox, QPushButton
class duo(QWidget):
def __init__(self,parent, text,choice):
super().__init__(parent)
layoutC = QHBoxLayout()
layoutC.addWidget(QLabel(text))
options=QComboBox()
options.addItems(choice)
options.currentTextChanged.connect(self.text_changed)
layoutC.addWidget(options)
self.setLayout(layoutC)
def text_changed(self):
global choice1_is_selected,choice2_is_selected
choice1_is_selected = True
self.parent().button_is_selected()
class duoB(QWidget):
def __init__(self,parent,text,choice):
super().__init__(parent)
layoutB = QHBoxLayout()
layoutB.addWidget(QLabel(text))
options=QComboBox()
options.addItems(choice)
options.currentTextChanged.connect(self.text_changed)
layoutB.addWidget(options)
self.setLayout(layoutB)
def text_changed(self):
global choice1_is_selected,choice2_is_selected
choice2_is_selected = True
self.parent().button_is_selected()
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("Reproducible")
layout = QGridLayout()
layout.addWidget(QLabel("Block 1"),0,0)
text2 = 'Block 2'
select2 = ['Not selected','first','second']
widgetcomposite1 = duo(self, text2,select2)
layout.addWidget(widgetcomposite1,1,0)
text3 = 'Block 3'
select3 = ['Unselected','I','II']
widgetcomposite2 = duoB(self, text3,select3)
layout.addWidget(widgetcomposite2,2,0)
self.btn_download = QPushButton('Download')
layout.addWidget(self.btn_download,3,0)
self.setLayout(layout)
self.button_is_selected()
def button_is_selected(self):
if (choice1_is_selected == True) and (choice2_is_selected == True):
self.btn_download.setDisabled(False)
else:
self.btn_download.setDisabled(True)
app = QApplication(sys.argv)
choice1_is_selected = False
choice2_is_selected = False
window = MainWindow()
window.show()
app.exec()
This is the code.
I am using pyCharm and python 3.7
I am able to get the GUI with all the buttons but when i click on the button it won't show in the display box until I click on the display box that is if i click on "5" it won't show in the display box until i click on the display box.
I am using MacOsCatalina.
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QGridLayout
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QPushButton
from functools import partial
__version__ = "0.1"
ERROR_MSG = "ERROR"
>The Main GUI class
class calcgui(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("calc")
self.setFixedSize(300,300)
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
self._createDisplay()
self._createButtons()
def _createDisplay(self):
self.display = QLineEdit()
self.display.setFixedHeight(50)
self.display.setAlignment(Qt.AlignRight)
self.display.setReadOnly(True)
self.generalLayout.addWidget(self.display)
def _createButtons(self):
self.buttons = {}
buttonsLayout = QGridLayout()
buttons = {"7":(0,0),
"8":(0,1),
"9":(0,2),
"C":(0,3),
"/":(0,4),
"4":(1,0),
"5":(1,1),
"6":(1,2),
"*":(1,3),
"(":(1,4),
"1":(2,0),
"2":(2,1),
"3":(2,2),
"-":(2,3),
")":(2,4),
"0":(3,0),
"00":(3,1),
".":(3,2),
"+":(3,3),
"=":(3,4)
}
for btnText, pos in buttons.items():
self.buttons[btnText] = QPushButton(btnText)
self.buttons[btnText].setFixedSize(50,50)
buttonsLayout.addWidget(self.buttons[btnText],pos[0],pos[1])
self.generalLayout.addLayout(buttonsLayout)
def setDisplayText(self, text):
self.display.setText(text)
self.display.setFocus()
def DisplayText(self):
return self.display.text()
def clearDisplay(self):
self.setDisplayText("")
>This is the linking class
class pycalcu:
def __init__(self,model,view):
self._evaluate = model
self._view = view
self._connectSignals()
def _calculateResult(self):
result = self._evaluate(expression=self._view.DisplayText())
self._view.setDisplayText(result)
def _buildExpression(self,sub_exp):
if self._view.DisplayText() == ERROR_MSG:
self._view.clearDisplay()
expression = self._view.DisplayText() + sub_exp
self._view.setDisplayText(expression)
def _connectSignals(self):
for btnText, btn in self._view.buttons.items():
if btnText not in {"C","="}:
btn.clicked.connect(partial(self._buildExpression,btnText))
self._view.buttons["="].clicked.connect(self._calculateResult)
return self._view.display.returnPressed.connect(self._calculateResult)
self._view.buttons["C"].clicked.connect(self._view.clearDisplay)
def evaluateExpression(expression):
try:
result = str(eval(expression, {}, {}))
except Exception:
result = ERROR_MSG
return result
def main():
pycalc = QApplication(sys.argv)
view = calcgui()
view.show()
model = evaluateExpression
pycalcu(model=model,view=view)
sys.exit(pycalc.exec_())
if __name__ == "__main__":
main()
Sorry, I didn’t really delve into your program logic.
I noted the changes that I made.
Give it a try.
import sys
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget, QMainWindow,
QGridLayout, QVBoxLayout, QLineEdit, QPushButton)
from PyQt5.QtCore import Qt
from functools import partial
__version__ = "0.1"
ERROR_MSG = "ERROR"
# >The Main GUI class
class calcgui(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("calc")
self.setFixedSize(300,300)
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self.generalLayout = QVBoxLayout(self._centralWidget)
self._createDisplay()
self._createButtons()
def _createDisplay(self):
self.display = QLineEdit()
self.display.setFixedHeight(50)
self.display.setAlignment(Qt.AlignRight)
self.display.setReadOnly(True)
self.generalLayout.addWidget(self.display)
def _createButtons(self):
self.buttons = {}
buttonsLayout = QGridLayout()
buttons = {
"7":(0,0),
"8":(0,1),
"9":(0,2),
"C":(0,3),
"/":(0,4),
"4":(1,0),
"5":(1,1),
"6":(1,2),
"*":(1,3),
"(":(1,4),
"1":(2,0),
"2":(2,1),
"3":(2,2),
"-":(2,3),
")":(2,4),
"0":(3,0),
"00":(3,1),
".":(3,2),
"+":(3,3),
"=":(3,4)
}
for btnText, pos in buttons.items():
self.buttons[btnText] = QPushButton(btnText)
self.buttons[btnText].setFixedSize(50,50)
buttonsLayout.addWidget(self.buttons[btnText],pos[0],pos[1])
# <----
self.generalLayout.addLayout(buttonsLayout) # <----
def setDisplayText(self, text):
self.display.setText(text)
self.display.setFocus()
def DisplayText(self):
return self.display.text()
def clearDisplay(self):
self.setDisplayText("")
# >This is the linking class
class pycalcu:
def __init__(self,model, view):
self._evaluate = model
self._view = view
self._connectSignals()
def _calculateResult(self):
result = self._evaluate(expression=self._view.DisplayText())
self._view.setDisplayText(result)
def _buildExpression(self, sub_exp):
if self._view.DisplayText() == ERROR_MSG:
self._view.clearDisplay()
expression = self._view.DisplayText() + sub_exp
self._view.setDisplayText(expression)
def _connectSignals(self):
for btnText, btn in self._view.buttons.items():
if btnText not in {"C", "="}:
btn.clicked.connect(partial(self._buildExpression, btnText))
self._view.buttons["="].clicked.connect(self._calculateResult)
self._view.buttons["C"].clicked.connect(self._view.clearDisplay) # +++
return self._view.display.returnPressed.connect(self._calculateResult)
# ? self._view.buttons["C"].clicked.connect(self._view.clearDisplay) # ---
def evaluateExpression(expression):
try:
result = str(eval(expression, {}, {}))
except Exception:
result = ERROR_MSG
return result
def main():
pycalc = QApplication(sys.argv)
view = calcgui()
view.show()
model = evaluateExpression
pycalcu(model=model, view=view)
sys.exit(pycalc.exec_())
if __name__ == "__main__":
main()
i'm new in Python and PyQt4.
I want to ask "How to back to previous Window ?"
i have 2 file in here, file 'login' and 'signup'
here file login.py
import sys
from PyQt4.QtGui import QWidget, QPushButton, QLineEdit, QLabel, \
QApplication, QGridLayout
from signup import SignUp
class Login(QWidget):
def __init__(self):
super(Login, self).__init__()
self.setWindowTitle("Login")
self.login_window()
def login_window(self):
self.login_layout = QGridLayout()
self.login_button = QPushButton("Login")
self.signup_button = QPushButton("Sign Up")
self.login_layout.addWidget(self.login_button, 2, 0)
self.login_layout.addWidget(self.signup_button, 2, 1)
self.signup_button.clicked.connect(self.signup_show)
self.setLayout(self.login_layout)
self.show()
def signup_show(self):
self.signupshow = SignUp()
self.hide()
self.signupshow.show()
def check_signup(self):
SignUp.check_signup()
self.show()
def main():
app = QApplication(sys.argv)
login = Login()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
and here is signup.py
import sys
from PyQt4.QtGui import QWidget, QPushButton, QLineEdit, QLabel, \
QApplication, QGridLayout
class SignUp(QWidget):
def __init__(self):
super(SignUp, self).__init__()
self.setWindowTitle("Sign Up")
self.signup_window()
def signup_window(self):
self.signup_layout = QGridLayout()
self.signup_button = QPushButton("Sign Up")
self.signup_layout.addWidget(self.signup_button, 2, 0, 1, 0)
self.signup_button.clicked.connect(self.check_signup)
self.setLayout(self.signup_layout)
self.show()
def check_signup(self):
self.close()
def main():
app = QApplication(sys.argv)
signup = SignUp()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
my problem is, when i push button signup from signup.py, it's close but window Login is not show.
i think i don't have any trigger in signup.py for check_signup in login.py
in this code, i delete some Line Edit and Label. I think it's not a problem.
i hope someone will help, Thank you before :)
and if you answer this questtion, i hope you will explain a little bit of the logic, thank you again :)
I'm not really sure what you are trying to achieve (your description is kind of confusing), but let's start here. I put all your code in one file, since you need to import each other (which leads to cyclic import). Then, I just added these two lines
self.login = Login()
self.login.show()
into check_signup method of SignUp class, which pops-up Login window. If this is not your desired result, please let us know and provide us a better description. The code follows:
import sys
from PyQt4.QtGui import QWidget, QPushButton, QLineEdit, QLabel, \
QApplication, QGridLayout
class Login(QWidget):
def __init__(self):
super(Login, self).__init__()
self.setWindowTitle("Login")
self.login_window()
def login_window(self):
self.login_layout = QGridLayout()
self.login_button = QPushButton("Login")
self.signup_button = QPushButton("Sign Up")
self.login_layout.addWidget(self.login_button, 2, 0)
self.login_layout.addWidget(self.signup_button, 2, 1)
self.signup_button.clicked.connect(self.signup_show)
self.setLayout(self.login_layout)
self.show()
def signup_show(self):
self.signupshow = SignUp()
self.hide()
self.signupshow.show()
def check_signup(self):
SignUp.check_signup()
self.show()
class SignUp(QWidget):
def __init__(self):
super(SignUp, self).__init__()
self.setWindowTitle("Sign Up")
self.signup_window()
def signup_window(self):
self.signup_layout = QGridLayout()
self.signup_button = QPushButton("Sign Up")
self.signup_layout.addWidget(self.signup_button, 2, 0, 1, 0)
self.signup_button.clicked.connect(self.check_signup)
self.setLayout(self.signup_layout)
self.show()
def check_signup(self):
self.login = Login()
self.login.show()
self.close()
def main():
app = QApplication(sys.argv)
signup = SignUp()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You should rather use signal-slot connections:
import sys
from PyQt4 import QtGui, QtCore
class WidgetA(QtGui.QWidget):
open_b = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(WidgetA, self).__init__(parent)
self.resize(100, 100)
self.l = QtGui.QVBoxLayout()
self.close_btn = QtGui.QPushButton('Close')
self.b_btn = QtGui.QPushButton('Open B')
self.b_btn.clicked.connect(self.b_btn_clicked)
self.l.addWidget(self.close_btn)
self.l.addWidget(self.b_btn)
self.setLayout(self.l)
def b_btn_clicked(self):
self.open_b.emit()
self.hide()
class WidgetB(QtGui.QWidget):
open_a = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(WidgetB, self).__init__(parent)
self.resize(100, 100)
self.l = QtGui.QVBoxLayout()
self.close_btn = QtGui.QPushButton('Close')
self.close_btn.clicked.connect(self.hide)
self.a_btn = QtGui.QPushButton('Open A')
self.a_btn.clicked.connect(self.a_btn_clicked)
self.l.addWidget(self.close_btn)
self.l.addWidget(self.a_btn)
self.setLayout(self.l)
def a_btn_clicked(self):
self.open_a.emit()
self.hide()
def main():
app = QtGui.QApplication(sys.argv)
a = WidgetA()
b = WidgetB()
a.open_b.connect(lambda: b.show())
b.open_a.connect(lambda: a.show())
a.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
For past few days I was trying to solve the issue of widget movement. At some point I tried rewriting QComboBox classes with mouse signals but that did not work. As a work around I settled for parenting my widget to a QGraphicsWidget but once I try to add another item it does not display any more and I'm not sure what to do. Here is full test script:
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QApplication,QGraphicsItem, QGraphicsView, QGraphicsScene, QDesktopWidget, QCheckBox, QGroupBox, QPushButton, QGridLayout, QLabel, QLineEdit, QComboBox, QFont, QRadioButton, QButtonGroup, QWidget, QShortcut, QKeySequence, QIcon, QListView, QStandardItemModel, QStandardItem, QAction, QIntValidator, QListWidget, QProgressBar, QSpacerItem
from PyQt4.QtCore import QRect
from functools import partial
import sys
class node_GUI(QtGui.QWidget):
def __init__(self):
super(node_GUI, self).__init__()
class Main(QtGui.QMainWindow):
def __init__(self, *args):
super(Main, self).__init__(*args)#QtGui.QMainWindow.__init__(self)
self.init_defaults()
def init_defaults(self):
self.setGeometry(800,800,500,200)
self.lay_main = QGridLayout()
self.centralwidget = QtGui.QWidget()
self.centralwidget.setLayout(self.lay_main)
self.setCentralWidget(self.centralwidget)
btn_create_node = QPushButton("Create Node View")
btn_create_node.clicked.connect(self.create_node_view)
self.lay_main.addWidget(btn_create_node)
def showWindow(self,window):
window.show()
def printTest(self):
print "Start"
box = QGroupBox("subWidget")
box_btn = QPushButton("Test")
box_btn.clicked.connect(self.printTest)
le_edit = QLineEdit()
lay = QGridLayout()
box.setLayout(lay)
lay.addWidget(box_btn)
lay.addWidget(le_edit)
area = QtGui.QGraphicsWidget()
area.setMinimumSize(QtCore.QSizeF(400,300))
area.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
area.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
proxy = self.scene.addWidget(box)
proxy.setParentItem(area)
print "END"
def create_node_view(self):
print "creting node view"
window = node_GUI()
window.setGeometry(QRect(100, 100, 400, 200))
window.setWindowTitle("node ")
window.setObjectName("node")
show_window = QPushButton("Show Node Editor")
show_window.setObjectName("btn")
show_window.clicked.connect(partial(self.showWindow,window))
self.lay_main.addWidget(show_window)
box = QGroupBox("Widgets")
box_btn = QPushButton("Test")
box_btn.clicked.connect(self.printTest)
le_edit = QLineEdit()
lay = QGridLayout()
box.setLayout(lay)
lay.addWidget(box_btn)
lay.addWidget(le_edit)
area = QtGui.QGraphicsWidget()
area.setMinimumSize(QtCore.QSizeF(300,300))
area.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
area.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
area.setAutoFillBackground(True)
ecs = QtGui.QGraphicsEllipseItem()
ecs.setRect(QtCore.QRectF(79,79,79,79))
ecs.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
ecs.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
view = QGraphicsView()
self.scene = QGraphicsScene()
self.scene.addItem(area)
proxy = self.scene.addWidget(box)
proxy.setParentItem(area)
self.scene.addItem(ecs)
view.setScene(self.scene)
lay_window = QGridLayout()
window.setLayout(lay_window)
lay_window.addWidget(view)
def main():
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
When you click on Create Node View > Show Node Editor > Test button > a new GroupBox should appear but that does not work. Not sure why.
Right so I stopped using QGraphicsWidget() and instead I just use QGraphicsRectItem(ecs for example) once I did that change everything started to work as expected.
I am learning PyQt5 now and tried to do something little on my own. I have made a very basic custom toolbox, which has just 6 QPushButtons buttons on it, which inherits from QWidget class.
My problem is that I can't display my toolbox on my QMainWidow instance. Let me show you what I did;
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class ToolBox(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
btn = [QPushButton('B', self) for i in range(6)]
for Btn in btn:
Btn.resize(30, 30)
self.resize(60, 90)
k = 0
for i in range(6):
btn[i].move((i%2)*30, k*30)
k += 1 if i % 2 == 1 else 0
self.show()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(300, 200)
self.statusBar().showMessage('Ready!')
exitAction = QAction(QIcon('idea.png'), 'Exit', self)
exitAction.setStatusTip('Exit application')
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(qApp.quit)
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('File')
fileMenu.addAction(exitAction)
t = ToolBox()
t.move(150, 150)
t.show() #With and without this line, it doesn't work.
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
m = MainWindow()
sys.exit(app.exec_())
You just need to position your widget somewhere in the QMainWindow canvas. All you have to do is position it in the MainWindow. Just for an example, I use setCentralWidget() to position your QWidget.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class ToolBox(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
btn = [QPushButton('B', self) for i in range(6)]
for Btn in btn:
Btn.resize(30, 30)
self.resize(60, 90)
k = 0
for i in range(6):
btn[i].move((i%2)*30, k*30)
k += 1 if i % 2 == 1 else 0
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(300, 200)
self.statusBar().showMessage('Ready!')
exitAction = QAction(QIcon('idea.png'), 'Exit', self)
exitAction.setStatusTip('Exit application')
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(qApp.quit)
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('File')
fileMenu.addAction(exitAction)
t = ToolBox()
self.setCentralWidget(t)
if __name__ == '__main__':
app = QApplication(sys.argv)
m = MainWindow()
m.show()
sys.exit(app.exec_())