I have a piece of PyQt5 code like this:
def displayDefaultParameters(self):
#Create Default Parameters
self.useDFParamsLabel = QLabel(self)
self.useDFParamsLabel.setText('Default Parameters:')
self.useDFParamsLabelFont = QFont("Calibri", 15)
self.useDFParamsLabelFont.setUnderline(True)
self.useDFParamsLabel.setFont(self.useDFParamsLabelFont)
self.useDFParamsLabel.setGeometry(QRect(650, 75, 220, 50))
self.useDFParamsLabel.show()
self.DFParamsQLabel = QLabel(self)
pixmap = QPixmap('question1.png')
self.DFParamsQLabel.setPixmap(pixmap)
self.DFParamsQLabel.setToolTip('Default Parameters when \nno input is provided.')
self.DFParamsQLabel.move(860,85)
#FIELDS THAT WILL BE CHANGED DYNAMICALLY
self.paramFont = QFont("Arial", 12, QFont.Bold)
self.DLabel = QLabel(self)
self.DLabel.setText('D = ' + str(self.D))
self.DLabel.setFont(self.paramFont)
self.DLabel.setGeometry(QRect(675, 110, 220, 50))
self.DLabel.show()
self.RoNLabel = QLabel(self)
self.RoNLabel.setText('R_on = ' + str(self.R_on) + ' \u03A9')
self.RoNLabel.setFont(self.paramFont)
self.RoNLabel.setGeometry(QRect(675, 135, 220, 50))
self.RoNLabel.show()
self.RoFFLabel = QLabel(self)
self.RoFFLabel.setText('R_off = ' + str(self.R_off) + ' \u03A9')
self.RoFFLabel.setFont(self.paramFont)
self.RoFFLabel.setGeometry(QRect(675, 160, 220, 50))
self.RoFFLabel.show()
As you can see self.D, self.R_on and self.R_off are class variables. Now I have initialized these class variables with some value, but it can be also user input. After the user inputs the value I need to be able to change the values. As for how the class values will be input by the user is through a form which looks like the form on this question. After clicking 'OK' the new values should be reflected.
So far whatever I have tried it is overwriting on previous values. How can we implement this?
You have to use the signals to notify changes to the other parts of the application, in this case create a model that every time a property is changed it will be notified through signals, that signals will be connected to a slot, and in that slot it will modify the GUI.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Model(QtCore.QObject):
D_Changed = QtCore.pyqtSignal(float)
R_on_Changed = QtCore.pyqtSignal(float)
R_off_Changed = QtCore.pyqtSignal(float)
W_0_Changed = QtCore.pyqtSignal(float)
def __init__(self, parent=None):
super(Model, self).__init__(parent)
self._d = 0.0
self._r_on = 0.0
self._r_off = 0.0
self._w_0 = 0.0
def D(self):
return self._d
def setD(self, d):
if self._d == d: return
self._d = d
self.D_Changed.emit(d)
def R_on(self):
return self._r_on
def setR_on(self, r_on):
if self._r_on == r_on: return
self._r_on = r_on
self.R_on_Changed.emit(r_on)
def R_off(self):
return self._r_off
def setR_off(self, r_off):
if self._r_off == r_off: return
self._r_off = r_off
self.R_off_Changed.emit(r_off)
D = QtCore.pyqtProperty(float, fget=D, fset=setD, notify=D_Changed)
R_on = QtCore.pyqtProperty(float, fget=R_on, fset=setR_on, notify=R_on_Changed)
R_off = QtCore.pyqtProperty(float, fget=R_off, fset=setR_off, notify=R_off_Changed)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
model = Model(self)
self.d_label = QtWidgets.QLabel()
self.r_on_label = QtWidgets.QLabel()
self.r_off_label = QtWidgets.QLabel()
model.D_Changed.connect(self.on_D_Changed)
model.R_on_Changed.connect(self.on_R_on_Changed)
model.R_off_Changed.connect(self.on_R_off_Changed)
model.setD(10.0)
model.setR_on(100)
model.setR_off(16000)
d_le = QtWidgets.QDoubleSpinBox(
maximum=sys.float_info.max,
value=model.D,
valueChanged=model.setD
)
r_on_le = QtWidgets.QDoubleSpinBox(
maximum=sys.float_info.max,
value=model.R_on,
valueChanged=model.setR_on
)
r_off_le = QtWidgets.QDoubleSpinBox(
maximum=sys.float_info.max,
value=model.R_off,
valueChanged=model.setR_off
)
groub_box_input = QtWidgets.QGroupBox("Edit Values")
flay = QtWidgets.QFormLayout()
flay.addRow("D (nm)", d_le)
flay.addRow("R_on (\u03A9)", r_on_le)
flay.addRow("R_off (\u03A9)", r_off_le)
groub_box_input.setLayout(flay)
groub_box_output = QtWidgets.QGroupBox("Default Parameters:")
vlay = QtWidgets.QVBoxLayout()
vlay.addWidget(self.d_label)
vlay.addWidget(self.r_on_label)
vlay.addWidget(self.r_off_label)
groub_box_output.setLayout(vlay)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(groub_box_input)
lay.addWidget(groub_box_output)
#QtCore.pyqtSlot(float)
def on_D_Changed(self, d):
self.d_label.setText('D = {}'.format(d))
#QtCore.pyqtSlot(float)
def on_R_on_Changed(self, r_on):
self.r_on_label.setText('R_on = {}\u03A9'.format(r_on))
#QtCore.pyqtSlot(float)
def on_R_off_Changed(self, r_off):
self.r_off_label.setText('R_off = {}\u03A9'.format(r_off))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app.setStyle("fusion")
w = Widget()
w.show()
sys.exit(app.exec_())
Related
My issue is that although I can get the program running correctly the first time, I am unable to edit my userList after I press the roll button.
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLineEdit, QPushButton, QScrollArea, QHBoxLayout, QCompleter,
QWidget, QVBoxLayout, QLabel, QSpacerItem, QSizePolicy)
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
import random
import sys
# create widget that will add and remove characters from the roulette pool
class AddRemoveWidget(QWidget):
def __init__(self, name, userList):
super(AddRemoveWidget, self).__init__()
self.name = name
# create a separate list as out roulette pool
self.userList = userList
self.added = False
# set up add and remove buttons
self.label = QLabel(self.name)
self.button_removed = QPushButton("Remove")
self.button_add = QPushButton("Add")
# set up the "box" for interaction
self.hBox = QHBoxLayout()
self.hBox.addWidget(self.label)
self.hBox.addWidget(self.button_removed)
self.hBox.addWidget(self.button_add)
# attribute functions to each button
self.button_add.clicked.connect(self.add)
self.button_removed.clicked.connect(self.remove)
self.setLayout(self.hBox)
self.update_button_state()
def show(self):
for w in [self, self.label, self.button_add, self.button_removed]:
w.setVisible(True)
def hide(self):
for w in [self, self.label, self.button_add, self.button_removed]:
w.setVisible(False)
def add(self, name):
self.added = True
self.userList.append(self.name)
self.update_button_state()
#return self.userList
def remove(self, name):
self.added = False
self.update_button_state()
self.userList.remove(self.name)
#return self.userList
def update_button_state(self):
if self.added == True:
self.button_add.setStyleSheet("background-color: #32CD32; color #fff;")
self.button_removed.setStyleSheet("background-color: none; color: none;")
else:
self.button_add.setStyleSheet("background-color: none; color: none;")
self.button_removed.setStyleSheet("background-color: #D32F2f; color: #fff")
# create main window (think of this as the main())
class MyWindow(QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.initUI()
def addCharToList(self, character):
self.charList.append(character)
def initUI(self):
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.userList = []
# list of elements
charactersAll = # assume generic stuff
self.widgets = []
for name in charactersAll:
item = AddRemoveWidget(name, self.userList)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.setWindowTitle("Rolling")
self.setGeometry(200, 200, 1024, 680)
self.label1 = QtWidgets.QLabel(self)
self.label1.setText("<h1>Roulette</h1>")
self.label1.adjustSize()
self.label1.move(10, 15)
self.label2 = QtWidgets.QLabel(self)
self.label2.setText("Add Characters to Roulette")
self.label2.setFont(QtGui.QFont('Comic_Sans', 15))
self.label2.move(10, 55)
self.label2.adjustSize()
self.label3 = QtWidgets.QLabel(self)
self.label3.setText("<h1>Team 1:</h1>")
self.label3.adjustSize()
self.label3.move(540, 30)
self.label4 = QtWidgets.QLabel(self)
self.label4.setText("")
self.label4.move(540, 70)
self.label5 = QtWidgets.QLabel(self)
self.label5.setText("")
self.label5.move(540, 85)
self.label6 = QtWidgets.QLabel(self)
self.label6.setText("")
self.label6.move(540, 100)
self.label7 = QtWidgets.QLabel(self)
self.label7.setText("<h1>Team 2:</h1>")
self.label7.adjustSize()
self.label7.move(540, 120)
self.label8 = QtWidgets.QLabel(self)
self.label8.setText("")
self.label8.move(540, 145)
self.label9 = QtWidgets.QLabel(self)
self.label9.setText("")
self.label9.move(540, 160)
self.label10 = QtWidgets.QLabel(self)
self.label10.setText("")
self.label10.move(540, 175)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(False)
self.scroll.setWidget(self.controls)
self.searchBar = QLineEdit()
self.searchBar.adjustSize()
self.searchBar.textChanged.connect(self.updateDisplay)
self.completer = QCompleter(charactersAll)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchBar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchBar)
containerLayout.addWidget(self.scroll)
containerLayout.setContentsMargins(10, 85, 0, 0)
container.setLayout(containerLayout)
container.setFixedSize(400, 600)
self.setCentralWidget(container)
self.b1 = QtWidgets.QPushButton(self)
self.b1.setText("Roll")
self.b1.setGeometry(10, 610, 390, 40)
self.b1.clicked.connect(self.RandRoll)
def updateDisplay(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
def updateText(self):
self.label4.adjustSize()
self.label6.adjustSize()
def RandRoll(self):
#create a separate list to save "names" for rerolls
self.tempList = []
selectedString = random.choice(self.userList)
self.tempList.append(selectedString)
self.label4.setText(selectedString + ", ")
self.userList.remove(selectedString)
selectedString = random.choice(self.userList)
self.tempList.append(selectedString)
self.label5.setText(selectedString + ", ")
self.userList.remove(selectedString)
selectedString = random.choice(self.userList)
self.tempList.append(selectedString)
self.label6.setText(selectedString)
self.userList.remove(selectedString)
selectedString = random.choice(self.userList)
self.tempList.append(selectedString)
self.label8.setText(selectedString + ", ")
self.userList.remove(selectedString)
selectedString = random.choice(self.userList)
self.tempList.append(selectedString)
self.label9.setText(selectedString + ", ")
self.userList.remove(selectedString)
selectedString = random.choice(self.userList)
self.tempList.append(selectedString)
self.label10.setText(selectedString)
self.userList.remove(selectedString)
# add back all "removed" names into userList
self.userList = self.userList + self.tempList
def window():
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec_())
window()
I'm thinking it is a problem with my add and remove functions under the AddRemoveWidget but I can't seem to figure out what's wrong.
There are actually various problems, but the main issue is that you're accessing (and, most importantly, modifying) the same list from objects that should not do it.
This happens here:
# create a separate list as out roulette pool
self.userList = userList
You are not creating a separate list, you're just setting the same list as an instance attribute, but the object is shared amongst the main window instance and all AddRemoveWidget widgets.
Instead of adding and removing items from the AddRemoveWidget, just connect its buttons to the main class and let that manage the contents of the list.
class AddRemoveWidget(QWidget):
def __init__(self, name):
super(AddRemoveWidget, self).__init__()
self.name = name
self.added = False
# ...
def add(self, name):
self.added = True
self.update_button_state()
def remove(self, name):
self.added = False
self.update_button_state()
# ...
class MyWindow(QMainWindow):
# ...
def initUI(self):
# ...
for name in charactersAll:
item = AddRemoveWidget(name)
item.button_add.clicked.connect(lambda _, name=name: self.addName(name))
item.button_removed.clicked.connect(lambda _, name=name: self.removeName(name))
self.controlsLayout.addWidget(item)
self.widgets.append(item)
# ...
def addName(self, name):
if not name in self.userList:
self.userList.append(name)
def removeName(self, name):
if name in self.userList:
self.userList.remove(name)
Note that I used a lambda in order to send the name parameter to the functions, but I set that parameter as a keyword after a _ argument. This is because clicked always sends a checked parameter when emitted (and you're not interested in that) and the name argument must be set within the scope of the lambda (otherwise it will always be the last value in the for cycle). Do some research about lambda scope in for/while loops to know more.
Also note that I didn't add the RandRoll function, as I've not really understood what you're going to do there, but consider that it has an important issue: since you're always removing items from the list, you'll probably end up in having an empty list, which will cause a crash in for choice, as it raises an exception if the argument is an empty sequence.
Finally, remove both the show() and hide() implementations, as they are unnecessary (and potentially wrong).
I want to run a AnimationGroup with different changing animations.
But the problem is that the function clear()
self.group = QtCore.QSequentialAnimationGroup(self)
def anim(self):
if X == True:
self.group.addAnimation(self.animation_1)
self.group.addAnimation(self.animation_2)
elif X == False:
self.group.addAnimation(self.animation_3)
self.group.addAnimation(self.animation_4)
self.group.start()
self.group.clear()
displays an error
RuntimeError: wrapped C/C++ object of type QVariantAnimation has been deleted
I can’t constantly create a new group.
def anim(self):
self.group = QtCore.QSequentialAnimationGroup(self)
if X == True:
self.group.addAnimation(self.animation_1)
self.group.addAnimation(self.animation_2)
elif X == False:
self.group.addAnimation(self.animation_3)
self.group.addAnimation(self.animation_4)
self.group.start()
self.group.clear()
I tried to use removeAnimation
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class Rad(QtWidgets.QWidget):
def __init__(self, group, pos, parent=None):
super(Rad, self).__init__(parent)
self.resize(50, 50)
lay = QtWidgets.QVBoxLayout(self)
self.radio = QtWidgets.QRadioButton()
self.label = QtWidgets.QLabel()
self.label.setText('but-{}'.format(pos))
self.group = group
self.pos = pos
lay.addWidget(self.radio)
lay.addWidget(self.label)
self.radio.toggled.connect(self.fun)
self.animation = QtCore.QVariantAnimation()
self.animation.setDuration(1000)
self.animation.valueChanged.connect(self.value)
self.animation.setStartValue(100)
self.animation.setEndValue(0)
self.can = False
def value(self, val):
self.move(self.pos, val)
def fun(self):
self.animation.setStartValue(
100
if not self.can
else 0
)
self.animation.setEndValue(
0
if not self.can
else 100
)
if self.group.animationAt(1) == None :
print("Bad")
else :
print("Good")
self.group.removeAnimation(self.group.animationAt(0))
self.group.addAnimation(self.animation)
self.group.start()
self.can = not self.can
class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.group = QtCore.QSequentialAnimationGroup(self)
self.buts = QtWidgets.QButtonGroup(self, exclusive=True)
wid_1 = Rad(self.group, 200, self)
wid_2 = Rad(self.group, 100, self)
wid_3 = Rad(self.group, 0, self)
self.buts.addButton(wid_1.radio, 0)
self.buts.addButton(wid_2.radio,1)
self.buts.addButton(wid_3.radio, 2)
wid_1.setStyleSheet('background:brown;')
wid_2.setStyleSheet('background:yellow;')
wid_3.setStyleSheet('background:green;')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Test()
w.resize(500, 500)
w.show()
sys.exit(app.exec_())
And now the animation has become sharp
And in the console output
QAnimationGroup::animationAt: index is out of bounds
From what I can deduce is that you want the pressed item to move down and if any item was in the low position then it must return to its position. If so then my answer should work.
You should not use the clear method since that removes and deletes the animation, instead use takeAnimation(0) until there are no animations, and just add the new animations, but that logic should not be inside "Rad" but in the Test class:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class Rad(QtWidgets.QWidget):
def __init__(self, text, parent=None):
super(Rad, self).__init__(parent)
self.resize(50, 50)
self.radio = QtWidgets.QRadioButton()
self.label = QtWidgets.QLabel()
self.label.setText(text)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.radio)
lay.addWidget(self.label)
self.animation = QtCore.QVariantAnimation()
self.animation.setDuration(1000)
self.animation.valueChanged.connect(self.on_value_changed)
self.animation.setStartValue(100)
self.animation.setEndValue(0)
#QtCore.pyqtSlot("QVariant")
def on_value_changed(self, val):
pos = self.pos()
pos.setY(val)
self.move(pos)
def swap_values(self):
self.animation.blockSignals(True)
start_value = self.animation.startValue()
end_value = self.animation.endValue()
self.animation.setStartValue(end_value)
self.animation.setEndValue(start_value)
self.animation.blockSignals(False)
class Test(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.buts = QtWidgets.QButtonGroup(self, exclusive=True)
wid_1 = Rad("but-200", self)
wid_1.setStyleSheet("background:brown;")
wid_1.move(200, 0)
wid_2 = Rad("but-100", self)
wid_2.setStyleSheet("background:yellow;")
wid_2.move(100, 0)
wid_3 = Rad("but-0", self)
wid_3.setStyleSheet("background:green;")
wid_3.move(0, 0)
self.buts.addButton(wid_1.radio, 0)
self.buts.addButton(wid_2.radio, 1)
self.buts.addButton(wid_3.radio, 2)
self.buts.buttonToggled.connect(self.on_button_toggled)
self.group = QtCore.QSequentialAnimationGroup(self)
self.last_widget = None
#QtCore.pyqtSlot(QtWidgets.QAbstractButton, bool)
def on_button_toggled(self, button, state):
if state:
wid = button.parent()
if self.group.animationCount() > 0:
self.group.takeAnimation(0)
if isinstance(self.last_widget, Rad):
self.last_widget.swap_values()
self.group.addAnimation(self.last_widget.animation)
wid.swap_values()
self.group.addAnimation(wid.animation)
self.group.start()
self.last_widget = wid
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Test()
w.resize(500, 500)
w.show()
sys.exit(app.exec_())
I would like to get values from Qdialog window into Qmainwindow after closing Qdailog or Qwidget window. Actually I do not know how to do this.
The idea is when user selects a root value from QtableWidget, as shown below in the figure, Data display on the QWidget and I want to transform or pass these values into my Qmainwindow, and my second window in this case is Circular.py would disappear, but my values should be available in the Qmainwindow.
Visualisation of windows.
The Code, "main.py"
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from Circular import *
class Foo(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Foo, self).__init__(parent)
self.setGeometry(QtCore.QRect(200, 100, 600, 360))
self.boo = Boo()
self.setCentralWidget(self.boo)
class Boo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Boo, self).__init__(parent)
Openbutton = QtWidgets.QPushButton('Getting values')
Alay = QtWidgets.QVBoxLayout(self)
Alay.addWidget(Openbutton)
Openbutton.clicked.connect(self.buttonfunc)
def buttonfunc(self):
app.setStyleSheet(QSS)
subwindow=CircularDialog()
subwindow.setWindowModality(QtCore.Qt.ApplicationModal)
subwindow.show()
subwindow.exec_()
print('Test')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Foo()
w.show()
sys.exit(app.exec_())
Second window code "Circular.py"
Please note that this code is previuosly posted here.
import sys
import os
from PyQt5 import QtCore, QtGui, QtWidgets
iconroot = os.path.dirname(__file__)
ORGANIZATION_NAME = 'Circular App'
ORGANIZATION_DOMAIN = 'Circular shape'
APPLICATION_NAME = 'Circulargeometry program'
SETTINGS_TRAY = 'settings/tray'
QSS = """
QTreeWidget{
border:none;
}
QTreeView::branch:has-siblings:!adjoins-item {
border-image: url(images/vline.png) 0;
}
QTreeView::branch:has-siblings:adjoins-item {
border-image: url(images/branch-more.png) 0;
}
QTreeView::branch:!has-children:!has-siblings:adjoins-item {
border-image: url(images/branch-end.png) 0;
}
QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
border-image: none;
image: url(images/branch-closed.png);
}
QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(images/branch-open.png);
}
"""
class TreeWidget(QtWidgets.QTreeWidget):
currentTextChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(TreeWidget, self).__init__(parent)
self.currentItemChanged.connect(self.onCurrentItemChanged)
self.setHeaderLabel('Standard Section Library')
self.setRootIsDecorated(True)
self.setAlternatingRowColors(True)
self.readSettings()
self.expandAll()
def onCurrentItemChanged(self, current, previous):
if current not in [self.topLevelItem(ix) for ix in range(self.topLevelItemCount())]:
self.currentTextChanged.emit(current.text(0))
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("TreeWidget")
values = settings.value("items")
if values is None:
self.loadDefault()
else:
TreeWidget.dataToChild(values, self.invisibleRootItem())
self.customized_item = None
for ix in range(self.topLevelItemCount()):
tlevel_item = self.topLevelItem(ix)
if tlevel_item.text(0) == "Customized":
self.customized_item = tlevel_item
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("TreeWidget")
settings.setValue("items", TreeWidget.dataFromChild(self.invisibleRootItem()))
settings.endGroup()
def loadDefault(self):
standardsectionlist = ["D100","D150","D200","D250","D300","D350","D400","D450","D500",
"D550","D600","D650","D700","D750","D800","D850","D900","D950","D1000"]
rootItem = QtWidgets.QTreeWidgetItem(self, ['Circular shapes'])
rootItem.setIcon(0, QtGui.QIcon(os.path.join(iconroot,"images/circularcolumnnorebar.png")))
for element in standardsectionlist:
rootItem.addChild(QtWidgets.QTreeWidgetItem([element]))
self.customized_item = QtWidgets.QTreeWidgetItem(self, ["Customized"])
self.customized_item.setIcon(0, QtGui.QIcon(os.path.join(iconroot,"images/circularcolumnnorebar.png")))
#staticmethod
def dataToChild(info, item):
TreeWidget.tupleToItem(info["data"], item)
for val in info["childrens"]:
child = QtWidgets.QTreeWidgetItem()
item.addChild(child)
TreeWidget.dataToChild(val, child)
#staticmethod
def tupleToItem(t, item):
# set values to item
ba, isSelected = t
ds = QtCore.QDataStream(ba)
ds >> item
item.setSelected(isSelected)
#staticmethod
def dataFromChild(item):
l = []
for i in range(item.childCount()):
child = item.child(i)
l.append(TreeWidget.dataFromChild(child))
return {"childrens": l, "data": TreeWidget.itemToTuple(item)}
#staticmethod
def itemToTuple(item):
# return values from item
ba = QtCore.QByteArray()
ds = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
ds << item
return ba, item.isSelected()
class InfoWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(InfoWidget, self).__init__(parent)
hlay = QtWidgets.QHBoxLayout(self)
plabel = QtWidgets.QLabel()
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/circularcolumnnorebard.png"))\
.scaled(230, 230, QtCore.Qt.KeepAspectRatio)
plabel.setPixmap(pixmap)
hlay.addWidget(plabel)
self.ilabel = QtWidgets.QLabel()
hlay.addWidget(self.ilabel)
hlay.addStretch()
self.readSettings()
#QtCore.pyqtSlot(str)
def setData(self, text):
try:
circular_section = int(text.translate({ord('D'): ""}))
area = (3.1416/4)*(circular_section**2)
inertia = (3.1416/64)*circular_section**4
fmt = "D = {}mm\nA = {:0.2E}mm2\n I = {:0.2E}mm4"
self.ilabel.setText(fmt.format(circular_section, area, inertia))
except ValueError:
pass
return print(circular_section)
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("InfoWidget")
self.ilabel.setText(settings.value("text", ""))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("InfoWidget")
settings.setValue("text", self.ilabel.text())
settings.endGroup()
class CircularDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(CircularDialog, self).__init__(parent)
self.setWindowTitle("Frequently used shape")
self.setWindowIcon(QtGui.QIcon(os.path.join(iconroot+"/images/circularcolumnnorebar.png")))
grid = QtWidgets.QGridLayout(self)
self.tree = TreeWidget()
self.infoWidget = InfoWidget()
section_lay = QtWidgets.QHBoxLayout()
section_label = QtWidgets.QLabel("Section name: ")
self.section_edit = QtWidgets.QLineEdit('Define en name to section')
section_lay.addWidget(section_label)
section_lay.addWidget(self.section_edit)
self.tree.currentTextChanged.connect(self.infoWidget.setData)
button_layout = QtWidgets.QVBoxLayout()
add_button = QtWidgets.QPushButton("Add")
add_button.clicked.connect(self.addItem)
delete_button = QtWidgets.QPushButton("Delete")
delete_button.clicked.connect(self.removeItem)
button_layout.addWidget(add_button, alignment=QtCore.Qt.AlignBottom)
button_layout.addWidget(delete_button, alignment=QtCore.Qt.AlignTop)
buttonBox = QtWidgets.QDialogButtonBox()
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
self.accepted.connect(self.save_all_data)
self.rejected.connect(self.save_all_data)
grid.addLayout(section_lay, 0, 0)
grid.addWidget(self.tree, 1, 0)
grid.addLayout(button_layout, 1, 1)
grid.addWidget(self.infoWidget, 2, 0, 1, 2)
grid.addWidget(buttonBox, 3, 0, 1, 2)
self.readSettings()
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("CircularDialog")
self.setGeometry(settings.value("geometry", QtCore.QRect(300, 300, 400, 600)))
self.section_edit.setText(settings.value("SectionInfo", "Define en name to section"))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("CircularDialog")
settings.setValue("geometry", self.geometry())
settings.setValue("SectionInfo",self.section_edit.text())
settings.endGroup()
def closeEvent(self, event):
self.save_all_data()
super(CircularDialog, self).closeEvent(event)
def save_all_data(self):
for children in self.findChildren(QtWidgets.QWidget) + [self]:
if hasattr(children, "writeSettings"):
children.writeSettings()
def addItem(self):
text, ok = QtWidgets.QInputDialog.getText(self, "Add custom section",
"Enter section geometry f.ex as D325 or just 325 in mm: ")
if ok:
it = QtWidgets.QTreeWidgetItem([text])
self.tree.customized_item.addChild(it)
def removeItem(self):
it = self.tree.customized_item.takeChild(0)
del it
if __name__ == '__main__':
QtCore.QCoreApplication.setApplicationName(ORGANIZATION_NAME)
QtCore.QCoreApplication.setOrganizationDomain(ORGANIZATION_DOMAIN)
QtCore.QCoreApplication.setApplicationName(APPLICATION_NAME)
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet(QSS)
w = CircularDialog()
w.show()
sys.exit(app.exec_())
The first thing to do is verify that if you accept or not using exec_ () that returns a code:QDialog::Accepted, if you want to get the text you must use the relationship tree:
def buttonfunc(self):
app.setStyleSheet(QSS)
subwindow=CircularDialog()
subwindow.setWindowModality(QtCore.Qt.ApplicationModal)
if subwindow.exec_() == QtWidgets.QDialog.Accepted:
print('Test', subwindow.infoWidget.ilabel.text())
I have created a widget with QLineEdit and QLabel, I want to get input from QlineEdit and display it with QLabel. I have used Signal and Slot connection, I do not know what I do wrong, but it is not working correctly. I would like to get both values from QLineEdit and later show it.
Current window
what I want?
Code:
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class WinDialog(QtWidgets.QDialog):
currenttextedited = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(WinDialog, self).__init__(parent)
self.setGeometry(300,300,350,300)
self.setWindowTitle("Signal & Slot")
self.propertyWidget = PropertyWidget()
section_lay = QtWidgets.QHBoxLayout()
section_label = QtWidgets.QLabel("Name: ")
section_edit = QtWidgets.QLineEdit('')
length_lay = QtWidgets.QHBoxLayout()
length_label = QtWidgets.QLabel("Input a number: L = ")
self.length_edit = QtWidgets.QLineEdit('1000')
self.length_edit.setInputMask("999999")
self.length_edit.setFocus(True)
thick_lay = QtWidgets.QHBoxLayout()
thick_label = QtWidgets.QLabel("Input a text: T = ")
thick_edit = QtWidgets.QLineEdit('')
section_lay.addWidget(section_label)
section_lay.addWidget(section_edit)
length_lay.addWidget(length_label)
length_lay.addWidget(self.length_edit)
length_lay.addStretch()
thick_lay.addWidget(thick_label)
thick_lay.addWidget(thick_edit)
thick_lay.addStretch()
VB_lay = QtWidgets.QVBoxLayout()
VB_lay.addStretch()
VB_lay.addLayout(length_lay)
VB_lay.addLayout(thick_lay)
VB_lay.addStretch()
buttonBox = QtWidgets.QDialogButtonBox()
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel
|QtWidgets.QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
grid = QtWidgets.QGridLayout(self)
grid.addLayout(section_lay, 0, 0, 1, 2)
grid.addLayout(VB_lay, 1, 0)
grid.addWidget(self.propertyWidget, 2, 0)
grid.addWidget(buttonBox, 3, 0, 1, 2)
self.length_edit.textEdited.connect(self.textchanged)
def textchanged(self, text):
print(text)
self.currenttextedited.emit(text)
class PropertyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(PropertyWidget, self).__init__(parent)
HB_lay = QtWidgets.QHBoxLayout(self)
self.Displaylabel = QtWidgets.QLabel('')
HB_lay.addWidget(self.Displaylabel)
HB_lay.addStretch()
#QtCore.pyqtSlot(int)
def Display(self, text):
try:
L_Display = int(text)
T_Display = int(text)
fmt = "L = {}mm\nT = {}mm"
self.Displaylabel.setText(fmt.format(L_Display, T_Display))
except ValueError:
print("Error")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = WinDialog()
w.show()
sys.exit(app.exec_())
according to samples in the image you want to show different texts but you are converting the same number to whole: L_Display = int(text) and T_Display = int(text) so how do you expect to show 2 different texts?, obviously the function display needs 2 entries (2 different entries to self plus I have changed to lowercase since it is recommended that the functions have a lowercase name).
Now the logic is as follows: if any of the texts of length_edit or thick_edit changes then you must call display() passing the new texts. So the solution is to use a slot that connects to the textEdited signals of both QLineEdits and in it obtain the text and pass the texts.
Finally I see that you want the QLineEdits receive only numbers so one option is to use a QIntValidator so that only numbers are acceptable (another better option is to use QSpinBox instead of QLineEdit)
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class WinDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(WinDialog, self).__init__(parent)
self.setGeometry(300,300,350,300)
self.setWindowTitle("Signal & Slot")
self.propertyWidget = PropertyWidget()
section_lay = QtWidgets.QHBoxLayout()
section_label = QtWidgets.QLabel("Name: ")
section_edit = QtWidgets.QLineEdit('')
length_lay = QtWidgets.QHBoxLayout()
length_label = QtWidgets.QLabel("Input a number: L = ")
self.length_edit = QtWidgets.QLineEdit()
self.length_edit.setFocus(True)
val_lenght = QtGui.QIntValidator(0, 100000, self.length_edit)
self.length_edit.setValidator(val_lenght)
thick_lay = QtWidgets.QHBoxLayout()
thick_label = QtWidgets.QLabel("Input a text: T = ")
self.thick_edit = QtWidgets.QLineEdit()
val_thick = QtGui.QIntValidator(0, 100000, self.thick_edit)
self.thick_edit.setValidator(val_thick)
section_lay.addWidget(section_label)
section_lay.addWidget(section_edit)
length_lay.addWidget(length_label)
length_lay.addWidget(self.length_edit)
length_lay.addStretch()
thick_lay.addWidget(thick_label)
thick_lay.addWidget(self.thick_edit)
thick_lay.addStretch()
VB_lay = QtWidgets.QVBoxLayout()
VB_lay.addStretch()
VB_lay.addLayout(length_lay)
VB_lay.addLayout(thick_lay)
VB_lay.addStretch()
buttonBox = QtWidgets.QDialogButtonBox()
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel
| QtWidgets.QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
grid = QtWidgets.QGridLayout(self)
grid.addLayout(section_lay, 0, 0, 1, 2)
grid.addLayout(VB_lay, 1, 0)
grid.addWidget(self.propertyWidget, 2, 0)
grid.addWidget(buttonBox, 3, 0, 1, 2)
self.length_edit.textEdited.connect(self.onTextEdited)
self.thick_edit.textEdited.connect(self.onTextEdited)
def onTextEdited(self):
l = self.length_edit.text()
t = self.thick_edit.text()
self.propertyWidget.display(l, t)
class PropertyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(PropertyWidget, self).__init__(parent)
HB_lay = QtWidgets.QHBoxLayout(self)
self.Displaylabel = QtWidgets.QLabel('')
HB_lay.addWidget(self.Displaylabel)
HB_lay.addStretch()
def display(self, l, t):
try:
L_Display = int(l)
T_Display = int(t)
fmt = "L = {}mm\nT = {}mm"
self.Displaylabel.setText(fmt.format(L_Display, T_Display))
except ValueError:
self.Displaylabel.clear()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = WinDialog()
w.show()
sys.exit(app.exec_())
I have a piece of code that is running, communication between two threads and status. I have faced with problem how to update QLineEdit field based on emitted value. So far, it works fine with commented lines, but it's not what I am looking for... How to modify show_process function to do the job...some help will be more than welcome?
import sys, time
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 200)
self.setWindowTitle("TEST APP!")
self.home()
def Label(self, name, width, length, fontSize) :
label_name = QtGui.QLabel(name, self)
label_name.move(width,length)
label_font = label_name.font()
label_font.setPointSize(fontSize)
label_name.setFont(label_font)
def Field(self, TrueFalse, width, length, startText) :
field_name = QtGui.QLineEdit(self)
field_name.setDisabled(TrueFalse)
field_name.move(width, length)
field_name.setAlignment(QtCore.Qt.AlignCenter)
field_name.setText(startText)
def home(self):
self.Label('TEST1', 10, 60, 10)
self.Label('TEST2', 10, 120, 10)
self.Field(True, 130, 60, 'Ready') # first one
self.Field(True, 130, 120, 'Ready') # second one
self.start = QtGui.QPushButton("start", self)
self.start.clicked.connect(self.startPressed)
self.start.move(260, 20)
self.stop = QtGui.QPushButton("Stop", self)
self.stop.clicked.connect(self.stopPressed)
self.stop.move(380, 20)
self.show()
def startPressed(self):
self.get_thread_start = Start_Process('239.200.10.1', 50010)
self.stop.clicked.connect(self.get_thread_start.terminate)
self.start.setDisabled(True)
self.get_thread_start.updated.connect(self.show_process)
self.get_thread_start.start()
def stopPressed(self):
self.start.setDisabled(False)
self.get_thread_start.running = False
def show_process(self, data):
if str(data) == '1' :
#self.textbox1.setText(str(data))
pass
elif str(data) == '0' :
#self.textbox2.setText(str(data))
pass
class Start_Process(QtCore.QThread):
updated = QtCore.pyqtSignal(int)
running = True
def __init__(self, mcstaddr, mcstport):
QtCore.QThread.__init__(self)
self.counter = 0
self.array = [1,0,1,0,1,0,1,0,1]
def run(self):
while self.running:
for i in self.array :
self.updated.emit(i)
time.sleep(0.5)
def main():
app = QtGui.QApplication(sys.argv)
GUI = Window()
GUI.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
A simple way to access the widget is to create a container, in this case we choose a dictionary:
self.field_dict = {}
Then we add in the Field() method we add the QLineEdits to the dictionary.
def Field(self, TrueFalse, width, length, startText, key) :
field_name = QtGui.QLineEdit(self)
...
self.field_dict[key] = field_name
Then we can get the QLineEdit through the key.
def show_process(self, key, data):
self.field_dict[key].setText(data)
Complete Example:
import sys, time
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 200)
self.setWindowTitle("TEST APP!")
self.field_dict = {}
self.home()
def Label(self, name, width, length, fontSize) :
label_name = QtGui.QLabel(name, self)
label_name.move(width,length)
label_font = label_name.font()
label_font.setPointSize(fontSize)
label_name.setFont(label_font)
def Field(self, TrueFalse, width, length, startText, key) :
field_name = QtGui.QLineEdit(self)
field_name.setDisabled(TrueFalse)
field_name.move(width, length)
field_name.setAlignment(QtCore.Qt.AlignCenter)
field_name.setText(startText)
self.field_dict[key] = field_name
def home(self):
self.Label('TEST1', 10, 60, 10)
self.Label('TEST2', 10, 120, 10)
self.Field(True, 130, 60, 'Ready', 0) # first one
self.Field(True, 130, 120, 'Ready', 1) # second one
self.start = QtGui.QPushButton("start", self)
self.start.clicked.connect(self.startPressed)
self.start.move(260, 20)
self.stop = QtGui.QPushButton("Stop", self)
self.stop.clicked.connect(self.stopPressed)
self.stop.move(380, 20)
self.show()
def startPressed(self):
self.get_thread_start = Start_Process('239.200.10.1', 50010)
self.stop.clicked.connect(self.get_thread_start.terminate)
self.start.setDisabled(True)
self.get_thread_start.updated.connect(self.show_process)
self.get_thread_start.start()
def stopPressed(self):
self.start.setDisabled(False)
self.get_thread_start.running = False
def show_process(self, key, data):
self.field_dict[key].setText(data)
class Start_Process(QtCore.QThread):
updated = QtCore.pyqtSignal(int, str)
running = True
def __init__(self, mcstaddr, mcstport):
QtCore.QThread.__init__(self)
self.counter = 0
self.array = [1,0,1,0,1,0,1,0,1]
def run(self):
while self.running:
for i in self.array :
self.updated.emit(i, str(self.counter))
time.sleep(0.5)
self.counter += 1
def main():
app = QtGui.QApplication(sys.argv)
GUI = Window()
GUI.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()