With a row of QListWidgets I wonder if there is a simple way to label each so the user would be able to say which List is which.
Here is a dialog's screenshot a code posted below results.
I avoid using any widgets outside of QListWidgets(). Ideal solution would be solved utilizing QListWidgets itself. It would be great if there is a way to place a text line-label similar to those available for QGroupBox with .setTitle('myString'). At very least an ability to place a label as a first list item would be sufficient too...
from PyQt4 import QtGui, QtCore
class MyApp(object):
def __init__(self):
super(MyApp, self).__init__()
app = QtGui.QApplication(sys.argv)
self.mainWidget = QtGui.QWidget()
self.mainLayout = QtGui.QVBoxLayout()
self.mainWidget.setLayout(self.mainLayout)
self.groupbox = QtGui.QGroupBox()
self.groupbox.setTitle('My Groupbox')
self.layout = QtGui.QVBoxLayout()
self.groupbox.setLayout(self.layout)
self.listGroupbox = QtGui.QGroupBox()
self.listLayout = QtGui.QHBoxLayout()
self.listGroupbox.setLayout(self.listLayout)
self.listA=QtGui.QListWidget()
self.listB=QtGui.QListWidget()
self.listLayout.addWidget(self.listA)
self.listLayout.addWidget(self.listB)
self.layout.addWidget(self.listGroupbox)
self.okButton = QtGui.QPushButton('OK')
self.okButton.clicked.connect(self.OK)
self.layout.addWidget(self.okButton)
self.mainLayout.addWidget(self.groupbox)
self.mainWidget.show()
sys.exit(app.exec_())
def OK(self):
print 'Ok'
if __name__ == '__main__':
MyApp()
Unfortunately there's no (Qt-native) way to label a QListView (on which QListWidget is based). If your really don't want additional widgets, I would instead use a single-column QTableWidget, and put the list title in the column header. QTableWidget and QListWidget work pretty similarly, so this probably won't break too much of your existing code.
An example based on yours:
class MyApp(object):
def __init__(self):
# snipped
self.listA = self.prepareTableWidget('List A')
self.listB = self.prepareTableWidget('List B')
# snipped
def prepareTableWidget(self, name):
table = QtGui.QTableWidget()
table.setColumnCount(1)
table.setHorizontalHeaderLabels([name])
table.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
return table
# snipped
Here is my attempt to achieve it without abandoning QListWidget()... utilizing layout's .insertLayout() method to attach QLabel without losing GUI space usually taken by QGroupBox()...
from PyQt4 import QtGui, QtCore
class MyApp(object):
def __init__(self):
super(MyApp, self).__init__()
app = QtGui.QApplication(sys.argv)
self.mainWidget = QtGui.QWidget()
self.mainLayout = QtGui.QVBoxLayout()
self.mainWidget.setLayout(self.mainLayout)
self.groupbox = QtGui.QGroupBox()
self.groupbox.setTitle('My Groupbox')
self.layout = QtGui.QVBoxLayout()
self.groupbox.setLayout(self.layout)
self.listGroupbox = QtGui.QGroupBox()
self.listLayout = QtGui.QHBoxLayout()
self.listGroupbox.setLayout(self.listLayout)
self.listA=QtGui.QListWidget()
self.listB=QtGui.QListWidget()
self.subLayoutA=QtGui.QVBoxLayout()
self.listLayout.insertLayout(0,self.subLayoutA)
self.subLayoutA.addWidget(QtGui.QLabel('Label A') )
self.subLayoutA.addWidget(self.listA)
self.subLayoutB=QtGui.QVBoxLayout()
self.listLayout.insertLayout(1,self.subLayoutB)
self.subLayoutB.addWidget(QtGui.QLabel('Label B') )
self.subLayoutB.addWidget(self.listB)
self.layout.addWidget(self.listGroupbox)
self.okButton = QtGui.QPushButton('OK')
self.okButton.clicked.connect(self.OK)
self.layout.addWidget(self.okButton)
self.mainLayout.addWidget(self.groupbox)
self.mainWidget.show()
sys.exit(app.exec_())
def OK(self):
print 'Ok'
if __name__ == '__main__':
MyApp()
Related
I am trying to get input from a user in one tab then show it in the second tab. I could not find a question or an example about how to do that. This is an example of the code that I want to use, How can I show the data from Tab(1) Qlabel in QTextEdit box in Tab(2), I am a beginner in pyqt5 and not sure how this would work:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class TabWidget(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle('Tab Widget Application')
tabwidget = QTabWidget()
tabwidget.addTab(FirstTab(), 'First Tab')
tabwidget.addTab(SecondTab(),'Second Tab')
vbox=QVBoxLayout()
vbox.addWidget(tabwidget)
self.setLayout(vbox)
class FirstTab(QWidget):
def __init__(self):
super().__init__()
self.nameLabel = QLabel(self)
self.nameLabel.setText('Name:')
self.line = QLineEdit(self)
self.line.move(80, 20)
self.line.resize(200, 32)
self.nameLabel.move(20, 20)
self.btn=QPushButton('switch',self)
self.btn.move(80, 50)
self.btn.clicked.connect(lambda: SecondTab.display(SecondTab(),self.nameLabel.text()))
class SecondTab(QWidget):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.editor=QTextEdit()
self.layout.addWidget(self.editor)
self.setLayout(self.layout)
def display(self,text):
self.editor.setText(text)
if __name__ == '__main__':
app=QApplication(sys.argv)
tabwidget = TabWidget()
tabwidget.resize(500,500)
tabwidget.show()
app.exec()
In order to track changes amongst child widgets, you'll need a main "controller".
Your QTabWidget will suffice, as long as you implement it in the correct way:
class TabWidget(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle('Tab Widget Application')
# if the target widget of the layout is provided as an init argument, the
# layout will be automatically set to it
vbox = QVBoxLayout(self)
tabwidget = QTabWidget()
vbox.addWidget(tabwidget)
firstTab = FirstTab()
tabwidget.addTab(firstTab, 'First Tab')
secondTab = SecondTab()
tabwidget.addTab(secondTab,'Second Tab')
firstTab.line.textChanged.connect(secondTab.editor.setPlainText)
firstTab.btn.clicked.connect(lambda: tabwidget.setCurrentWidget(secondTab))
Funny that this isn't better documented. But basically I'm just trying to get the value of a dropdown QComboBox in PyQT5 when I click a button.
Currently, when I use the following code, it is only giving me the value after I select a value in the dropdown. I am new to PyQt.
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.lineEdit = QLineEdit(self.centralwidget)
self.lineEdit.setObjectName("lineEdit")
self.templatetype = QComboBox(self.centralwidget)
self.templatetype.setObjectName("templatetype")
self.templatetype.addItem("Tracks")
self.templatetype.addItem("Observations")
self.templatetype.activated[str].connect(self.change_text)
self.btn = QPushButton(self.centralwidget)
self.btn.setObjectName("btn")
self.btn.clicked.connect(self.change_text)
def change_text(self,text):
self.lineEdit.setText(text)
Simple solution...
self.templatetype.activated[str].connect(self.change_text)
should be
self.templatetype.highlighted[str].connect(self.change_text)
Try it:
from PyQt5 import Qt
class MainWindow(Qt.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.main_widget = Qt.QWidget()
self.setCentralWidget(self.main_widget)
layout = Qt.QVBoxLayout(self.main_widget)
self.lineEdit = Qt.QLineEdit(self)
self.templatetype = Qt.QComboBox(self)
self.templatetype.addItem("Tracks")
self.templatetype.addItem("Observations")
self.templatetype.activated[str].connect(self.combo_text)
self.text = ""
self.btn = Qt.QPushButton("Button", self)
self.btn.clicked.connect(self.change_text)
layout.addWidget(self.lineEdit)
layout.addWidget(self.templatetype)
layout.addWidget(self.btn)
layout.setAlignment(Qt.Qt.AlignCenter)
def combo_text(self,text):
self.text = self.templatetype.currentText()
def change_text(self):
self.lineEdit.setText(self.text)
if __name__ == '__main__':
import sys
app = Qt.QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
I am not sure if I completely understood your question. You just want to get the text that is in the QComboBox when you click on the button? If that is the case then it's pretty simple. First you need to get the current text in the QComboBox then put it in the QLineEdit. Your don't need the to use a Signal here. So you can remove the following line:
self.templatetype.activated[str].connect(self.change_text)
And update your change_text method like this.
def change_text(self):
current_value = self.templatetype.currentText()
self.lineEdit.setText(current_value)
I have the following window with frames.
I want frame to be highlighted (in my case change its shape) when mouse is in its area.
from PyQt4 import QtGui, QtCore
import sys
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
window_layout = QtGui.QVBoxLayout()
window.setLayout(window_layout)
#fill content
for i in range(10):
label = QtGui.QLabel(str(i))
frame = QtGui.QFrame()
frame_layout = QtGui.QVBoxLayout()
frame.setLayout(frame_layout)
frame_layout.addWidget(label)
window_layout.addWidget(frame)
def layout_widgets(layout):
return (layout.itemAt(i) for i in range(layout.count()))
def mouse_enter(event):
print 'frame enter'
w.widget().setFrameShape(3)
def mouse_leave(event):
print 'frame leave'
w.widget().setFrameShape(0)
for w in layout_widgets(window_layout):
print w.widget()
w.widget().enterEvent = mouse_enter
w.widget().leaveEvent = mouse_leave
window.show()
sys.exit(app.exec_())
It works but only the last frame in layout highlights.
How to make only that frame change its shape where the mouse is?
I've tried the following:
def mouse_enter(event, frame):
print 'frame enter'
frame.setFrameShape(3)
w.widget().enterEvent = functools.partial(mouse_enter, w.widget())
but it gives an error. I have found one more way to do that - signal mapper
but I have no idea how to use it.
The problem in your code the variable w when executing the for is left with the last element, so it will only be executed in the latter. To solve this I have implemented a Frame class that inherits from QFrame where I overwrite the enterEvent and leaveEvent functions.
from PyQt4 import QtGui, QtCore
import sys
class Frame(QtGui.QFrame):
def __init__(self, text, parent=None):
super(Frame, self).__init__(parent=parent)
label = QtGui.QLabel(text)
frame_layout = QtGui.QVBoxLayout()
frame_layout.addWidget(label)
self.setLayout(frame_layout)
def enterEvent(self, event):
self.setFrameShape(3)
def leaveEvent(self, event):
self.setFrameShape(0)
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
window_layout = QtGui.QVBoxLayout()
window.setLayout(window_layout)
for i in range(10):
frame = Frame(str(i))
window_layout.addWidget(frame)
window.show()
sys.exit(app.exec_())
I am trying to set up a window that has a text input & a combo box. At the moment I just want to see the text & the selection displayed under the appropriate widget.
I have used QVBoxLayout() as I will be adding more stuff later & thought it would be a simple way of laying out the window.
Unfortunately only the combo box ever gets displayed. The code:
from PyQt4 import QtCore, QtGui
import sys
class Polyhedra(QtGui.QMainWindow):
def __init__(self):
super(Polyhedra, self).__init__()
self.initUI()
def initUI(self):
# Poly names
self.pNames = QtGui.QLabel(self)
polyNameInput = QtGui.QLineEdit(self)
# polyName entry
polyNameInput.textChanged[str].connect(self.onChanged)
# Polytype selection
self.defaultPolyType = QtGui.QLabel("Random polyhedra", self)
polyType = QtGui.QComboBox(self)
polyType.addItem("Random polyhedra")
polyType.addItem("Spheres")
polyType.addItem("Waterman polyhedra")
polyType.activated[str].connect(self.onActivated)
# Layout
vbox = QtGui.QVBoxLayout()
vbox.addWidget(polyNameInput)
vbox.addWidget(self.pNames)
vbox.addWidget(polyType)
vbox.addWidget(self.defaultPolyType)
vbox.addStretch()
# Set up window
self.setGeometry(500, 500, 300, 300)
self.setWindowTitle('Pyticle')
self.show()
# Combo box
def onActivated(self, text):
self.defaultPolyType.setText(text)
self.defaultPolyType.adjustSize()
# Poly names
def onChanged(self, text):
self.pNames.setText(text)
self.pNames.adjustSize()
def main():
app = QtGui.QApplication(sys.argv)
ex = Polyhedra()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
So whats going on here? Am I missing some important directive to QVBoxLayout()?
Using Python 2.7 on Win 7 x64 machine with PyQt 4.
EDIT: Additional problem (still related to missing widgets)
I have amended the code following the clarification below. I then added more widgets when a certain option in the combobox is chosen (see below) but these widgets dont show. I attempted to add a child widget to 'widget' called 'ranPolyWidget' to take a numerical input.
# Combo box
def onActivated(self, text):
if text=="Random polyhedra":
self.randomSeedLbl = QtGui.QLabel("Seed: ", self)
randomSeed = QtGui.QLineEdit(self)
randomSeed.textChanged[str].connect(self.setSeed)
ranPolyWidget = QtGui.QWidget(self.widget)
rbox = QtGui.QVBoxLayout(ranPolyWidget)
rbox.addWidget(randomSeed)
self.layout().addWidget(ranPolyWidget)
self.show()
else:
self.defaultPolyType.setText(text)
self.defaultPolyType.adjustSize()
Same issue as before, no widgets. I am missing something pretty fundamental arent I?
You're forgetting to set it to the widget or main window, so since the QComboBox is the last one made, it's the only one displayed. Basically, everything is added to the layout, but the layout is "free-floating", and so it does not display properly. You need to bind the layout to a QWidget, which I do here. For most widgets, you can can do this by the QtGui.QVBoxLayout(widget) or by widget.setLayout(layout).
Alternatively, if you want multiple layouts on a widget, you can do have a parent layout and then add each child layout to the main layout.
EDIT: This is a better answer:
Make a widget, set layout to widget and set as central widget.
QMainWindow-s don't like you using the builtin layout or overriding it.
widget = QtGui.QWidget()
vbox = QtGui.QVBoxLayout(widget)
self.setCentralWidget(widget)
Old Answer:
self.layout().addLayout(vbox).
This should fix your issue:
Changes I made:
Since QMainWindow already has a layout, add in a widget (28G) and then set the VBoxLayout to the widget and add it to the main window.
from PyQt4 import QtCore, QtGui
import sys
class Polyhedra(QtGui.QMainWindow):
def __init__(self):
super(Polyhedra, self).__init__()
self.initUI()
def initUI(self):
# Poly names
self.pNames = QtGui.QLabel(self)
polyNameInput = QtGui.QLineEdit(self)
# polyName entry
polyNameInput.textChanged[str].connect(self.onChanged)
# Polytype selection
self.defaultPolyType = QtGui.QLabel("Random polyhedra", self)
polyType = QtGui.QComboBox(self)
polyType.addItem("Random polyhedra")
polyType.addItem("Spheres")
polyType.addItem("Waterman polyhedra")
polyType.activated[str].connect(self.onActivated)
# Layout
widget = QtGui.QWidget()
vbox = QtGui.QVBoxLayout(widget)
vbox.addWidget(polyNameInput)
vbox.addWidget(self.pNames)
vbox.addWidget(polyType)
vbox.addWidget(self.defaultPolyType)
vbox.addStretch()
# Set up window
self.setGeometry(500, 500, 300, 300)
self.setWindowTitle('Pyticle')
self.layout().addWidget(widget)
self.show()
# Combo box
def onActivated(self, text):
self.defaultPolyType.setText(text)
self.defaultPolyType.adjustSize()
# Poly names
def onChanged(self, text):
self.pNames.setText(text)
self.pNames.adjustSize()
def main():
app = QtGui.QApplication(sys.argv)
ex = Polyhedra()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
EDIT:
For adding new widgets, you should add them to the layout of the central widget and parent them to that widget.
Here's how I'd restructure your full code:
from PyQt4 import QtCore, QtGui
import sys
class CentralWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(CentralWidget, self).__init__(parent)
# set layouts
self.layout = QtGui.QVBoxLayout(self)
# Poly names
self.pNames = QtGui.QLabel(self)
polyNameInput = QtGui.QLineEdit(self)
# polyName entry
polyNameInput.textChanged[str].connect(self.onChanged)
# Polytype selection
self.defaultPolyType = QtGui.QLabel("Random polyhedra", self)
polyType = QtGui.QComboBox(self)
polyType.addItem("Random polyhedra")
polyType.addItem("Spheres")
polyType.addItem("Waterman polyhedra")
polyType.activated[str].connect(self.onActivated)
self.layout.addWidget(polyNameInput)
self.layout.addWidget(self.pNames)
self.layout.addWidget(polyType)
self.layout.addWidget(self.defaultPolyType)
self.layout.addStretch()
def onActivated(self, text):
'''Adds randSeed to layout'''
if text=="Random polyhedra":
self.randomSeedLbl = QtGui.QLabel("Seed: ", self)
randomSeed = QtGui.QLineEdit(self)
randomSeed.textChanged[str].connect(self.setSeed)
self.layout.addWidget(randomSeed)
else:
self.defaultPolyType.setText(text)
self.defaultPolyType.adjustSize()
# Poly names
def onChanged(self, text):
self.pNames.setText(text)
self.pNames.adjustSize()
class Polyhedra(QtGui.QMainWindow):
def __init__(self):
super(Polyhedra, self).__init__()
# I like having class attributes bound in __init__
# Not very Qt of me, but it's more
# so I break everything down into subclasses
# find it more Pythonic and easier to debug: parent->child
# is easy when I need to repaint or delete child widgets
self.central_widget = CentralWidget(self)
self.setCentralWidget(self.central_widget)
# Set up window
self.setGeometry(500, 500, 300, 300)
self.setWindowTitle('Pyticle')
self.show()
# Combo box
def onActivated(self, text):
'''Pass to child'''
self.central_widget.onActivated(text)
def main():
app = QtGui.QApplication(sys.argv)
ex = Polyhedra()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Let's say I created two QObject in my interface (ui). I would like to connect these two widgets and let them controling each other depending on their visual status. If one is hidden, the other one must be visible. And vice versa.
Can you help me ? :)
Thanks !
Nico
Possible solution: Sublclass widgets and override hideEvent and showEvent:
#!/usr/bin/env python
import sys
from PyQt4 import QtCore, QtGui
class CustomWidget(QtGui.QLabel):
signal_hided = QtCore.pyqtSignal()
signal_shown = QtCore.pyqtSignal()
def hideEvent(self, event):
print 'hideEvent'
super(CustomWidget, self).hideEvent(event)
self.signal_hided.emit()
def showEvent(self, event):
print 'showEvent'
super(CustomWidget, self).showEvent(event)
self.signal_shown.emit()
class MainWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.widget1 = CustomWidget('Widget1')
self.widget2 = CustomWidget('Widget2')
# connect signals, so if one widget is hidden then other is shown
self.widget1.signal_hided.connect(self.widget2.show)
self.widget2.signal_hided.connect(self.widget1.show)
self.widget2.signal_shown.connect(self.widget1.hide)
self.widget1.signal_shown.connect(self.widget2.hide)
# some test code
self.button = QtGui.QPushButton('test')
layout = QtGui.QVBoxLayout()
layout.addWidget(self.button)
layout.addWidget(self.widget1)
layout.addWidget(self.widget2)
self.setLayout(layout)
self.button.clicked.connect(self.do_test)
def do_test(self):
if self.widget1.isHidden():
self.widget1.show()
else:
self.widget2.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
widget = MainWidget()
widget.resize(640, 480)
widget.show()
sys.exit(app.exec_())