I'm trying to get a lineEdit that have a cursor in it when a button is clicked. For example: I run application, put a cursor in one lineEdit, and when clicking a button - some text should be set in chosen lineEdit.
I've tried with keyboardGrabber, but it returns button =None.
import sys
from PyQt5 import QtWidgets, QtCore
class Mainwindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("window")
self.lineEdit1 = QtWidgets.QLineEdit()
self.lineEdit2 = QtWidgets.QLineEdit()
self.lineEdit3 = QtWidgets.QLineEdit()
self.pushButton = QtWidgets.QPushButton()
self.label = QtWidgets.QLabel()
self.label.setText('#1')
self.frame = QtWidgets.QFrame(self)
self.frame.setGeometry(QtCore.QRect(0, 0, 200, 100))
self.gridLayout = QtWidgets.QGridLayout(self.frame)
self.gridLayout.addWidget(self.lineEdit1, 0, 0, 1, 1)
self.gridLayout.addWidget(self.lineEdit2, 0, 1, 1, 1)
self.gridLayout.addWidget(self.lineEdit3, 0, 2, 1, 1)
self.gridLayout.addWidget(self.label, 0, 3, 1, 1)
self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
self.pushButton.clicked.connect(self.function)
def function(self):
widget = self.keyboardGrabber()
widget.setText('some text')
if __name__ == '__main__':
app = QtWidgets.QApplication([])
application = Mainwindow()
application.show()
Try it: void QApplication::focusChanged(QWidget *old, QWidget *now)
This signal is emitted when the widget that has keyboard focus changed from old to now, i.e., because the user pressed the tab-key, clicked into a widget or changed the active window. Both old and now can be nullptr.
import sys
from PyQt5 import QtWidgets, QtCore
class Mainwindow(QtWidgets.QMainWindow): # QMainWindow QWidget
def __init__(self):
super().__init__()
QtWidgets.qApp.focusChanged.connect(self.on_focusChanged) # +++
self.setWindowTitle("window")
self.lineEdit1 = QtWidgets.QLineEdit(self)
self.lineEdit1.setFocus() # +
self.lineEdit2 = QtWidgets.QLineEdit()
self.lineEdit3 = QtWidgets.QLineEdit()
self.pushButton = QtWidgets.QPushButton()
self.label = QtWidgets.QLabel()
self.label.setText('#1')
self.frame = QtWidgets.QFrame(self)
self.setCentralWidget(self.frame) # +
self.frame.setGeometry(QtCore.QRect(0, 0, 200, 100))
self.gridLayout = QtWidgets.QGridLayout(self.frame)
self.gridLayout.addWidget(self.lineEdit1, 0, 0, 1, 1)
self.gridLayout.addWidget(self.lineEdit2, 0, 1, 1, 1)
self.gridLayout.addWidget(self.lineEdit3, 0, 2, 1, 1)
self.gridLayout.addWidget(self.label, 0, 3, 1, 1)
self.gridLayout.addWidget(self.pushButton, 1, 0, 1, 1)
self.lineFocus = ... # +++
self.pushButton.clicked.connect(self.function)
def function(self):
# widget = self.keyboardGrabber()
# widget.setText('some text')
self.lineFocus.setText('some text')
#QtCore.pyqtSlot("QWidget*", "QWidget*")
def on_focusChanged(self, old, now): # +++
#print(f"\nold: {old}, now: {now}")
self.lineFocus = old
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
application = Mainwindow()
application.show()
sys.exit(app.exec_())
Related
I have the following code which shows me 7 of the widgets in a history window of my application. Each widget has a name, icon and an address to a previously opened file. I want all widgets to be clickable and write a function which exactly knows which widget was clicked. I have no clue on how to make a whole widget act as a single clickable item.
This is my code for showing the widgets.
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
for i in range (7):
self.gridLayoutWidget = QWidget(self)
self.gridLayoutWidget.setGeometry(QRect(40, 40 + i * 60, 350, 40))
self.gridLayout = QGridLayout(self.gridLayoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.Label1 = QLabel(self.gridLayoutWidget)
self.Label1.setText("the name of the file")
self.Label1.setFont(QFont('Arial', 14))
self.gridLayout.addWidget(self.Label1, 0, 1, 1, 9)
self.Label2 = QLabel(self.gridLayoutWidget)
self.Label2.setText("the address of the file")
self.gridLayout.addWidget(self.Label2, 1, 1, 1, 9)
self.im = QPixmap("img.ico")
self.icon = QLabel()
self.icon.setPixmap(self.im)
self.gridLayout.addWidget(self.icon , 0, 0, 2, 1)
In this case it is better to create a class that inherits from widget and implements the logic of the complex widget to avoid repetitive code that can cause problems (for example self.Label2 what does QLabel refer to? Does it refer to the first, the second, ...? , since it refers to the latter). On the other hand, that allows us to override the mouseReleaseEvent method, causing a signal to be emitted that later allows us to identify the widget using the sender method.
class GridLayoutWidget(QWidget):
clicked = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.Label1 = QLabel(text="the name of the file", font=QFont("Arial", 14))
self.Label2 = QLabel(text="the address of the file")
self.icon = QLabel(pixmap=QPixmap("img.ico"))
self.gridLayout = QGridLayout(self)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.addWidget(self.Label1, 0, 1, 1, 9)
self.gridLayout.addWidget(self.Label2, 1, 1, 1, 9)
self.gridLayout.addWidget(self.icon, 0, 0, 2, 1)
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
self.clicked.emit()
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
rect = QRect(40, 40, 350, 40)
for i in range(7):
widget = GridLayoutWidget(self)
widget.setGeometry(rect.translated(0, 60 * i))
widget.clicked.connect(self.handle_clicked)
self.resize(640, 480)
#pyqtSlot()
def handle_clicked(self):
widget = self.sender()
print(widget)
I am using QGridLayout in my project, and the code is:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
widget = QWidget()
self.setCentralWidget(widget)
layout = QGridLayout()
widget.setLayout(layout)
lay1 = QVBoxLayout()
lay1Header = QHBoxLayout()
lay1Header.addWidget(QLabel('lay1'))
lay1.addLayout(lay1Header)
label1 = QLabel('label1')
label1.setStyleSheet('background: rgb(255, 0, 0)')
lay1.addWidget(label1)
lay2 = QVBoxLayout()
lay2Header = QHBoxLayout()
lay2Header.addWidget(QLabel('lay2'))
lay2Header.addWidget(QLineEdit())
lay2.addLayout(lay2Header)
label2 = QLabel('label2')
label2.setStyleSheet('background: rgb(0, 0, 255)')
lay2.addWidget(label2)
layout.addLayout(lay1, 0, 0, 1, 1)
layout.addLayout(lay2, 0, 1, 1, 1)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
And the result is:
My environment is:
win 10
anaconda
pyqt5 5.14.0
How can I make the size of label1/label2 the same?
The size of the items in a QGridLayout depends on all the items in the column or row, not just one of them. So for this case the solution is to set the same alignment factor for the columns and set the height of the first QLabel to be that of the QLineEdit:
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
widget = QWidget()
self.setCentralWidget(widget)
layout = QGridLayout(widget)
lbl1 = QLabel("lay1")
lay1 = QVBoxLayout()
lay1Header = QHBoxLayout()
lay1Header.addWidget(lbl1)
lay1.addLayout(lay1Header)
label1 = QLabel("label1")
label1.setStyleSheet("background: rgb(255, 0, 0)")
lay1.addWidget(label1)
le1 = QLineEdit()
lay2 = QVBoxLayout()
lay2Header = QHBoxLayout()
lay2Header.addWidget(QLabel("lay2"))
lay2Header.addWidget(le1)
lay2.addLayout(lay2Header)
label2 = QLabel("label2")
label2.setStyleSheet("background: rgb(0, 0, 255)")
lay2.addWidget(label2)
layout.addLayout(lay1, 0, 0, 1, 1)
layout.addLayout(lay2, 0, 1, 1, 1)
layout.setColumnStretch(0, 1)
layout.setColumnStretch(1, 1)
lbl1.setFixedHeight(le1.sizeHint().height())
I am trying to build a simple GUI with PyQt5, where I have a few widgets which I want to align using QGridLayout.
Look at the following example code which I found on some website:
import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit,
QTextEdit, QGridLayout, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
title = QLabel('Title')
author = QLabel('Author')
review = QLabel('Review')
titleEdit = QLineEdit()
authorEdit = QLineEdit()
reviewEdit = QTextEdit()
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(title, 1, 0)
grid.addWidget(titleEdit, 1, 1)
grid.addWidget(author, 2, 0)
grid.addWidget(authorEdit, 2, 1)
grid.addWidget(review, 3, 0)
grid.addWidget(reviewEdit, 3, 1, 5, 1)
self.setLayout(grid)
self.setGeometry(300, 300, 350, 300)
self.setWindowTitle('Review')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Output
As you can see, there are three labels in the first column, each spanning one cell vertically and one cell horizontally.
In the second column there are two 1x1 widgets and one 5x1 widget.
Let's say I want to place another label called test and a lineedit called testEdit below.
Naively I would modify initUI() like this:
def initUI(self):
title = QLabel('Title')
author = QLabel('Author')
review = QLabel('Review')
test = QLabel('Test')
titleEdit = QLineEdit()
authorEdit = QLineEdit()
reviewEdit = QTextEdit()
testEdit = QTextEdit()
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(title, 1, 0)
grid.addWidget(titleEdit, 1, 1)
grid.addWidget(author, 2, 0)
grid.addWidget(authorEdit, 2, 1)
grid.addWidget(review, 3, 0)
grid.addWidget(reviewEdit, 3, 1, 5, 1)
grid.addWidget(test, 8, 0)
grid.addWidget(testEdit, 8, 1)
self.setLayout(grid)
self.setGeometry(300, 300, 350, 300)
self.setWindowTitle('Review')
self.show()
Where I just placed the new 1x1 widgets in the 8th row, below the previous one, which produces:
Output 2
However the result is not what I would expect, since the testEdit-widget is definitely not of size 1x1 and the reviewEdit-widget is also altered.
So why doesn't it work this way?
Try it:
import sys
from PyQt5.QtWidgets import (QWidget, QLabel, QLineEdit,
QTextEdit, QGridLayout, QApplication,
)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
title = QLabel('Title')
author = QLabel('Author')
review = QLabel('Review')
test = QLabel('Test')
titleEdit = QLineEdit()
authorEdit = QLineEdit()
reviewEdit = QTextEdit()
testEdit = QTextEdit()
testEdit.setMaximumHeight(20) # +++
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(title, 1, 0)
grid.addWidget(titleEdit, 1, 1)
grid.addWidget(author, 2, 0)
grid.addWidget(authorEdit, 2, 1)
grid.addWidget(review, 3, 0)
grid.addWidget(reviewEdit, 3, 1, 5, 1)
grid.addWidget(test, 8, 0)
grid.addWidget(testEdit, 8, 1)
self.setLayout(grid)
self.setGeometry(300, 300, 350, 300)
self.setWindowTitle('Review')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I have a QDialog that has multiple QLineEdit and QPushButton widgets. PySide highlights both, the first QLineEdit and the first QPushButton.
How can I make it focus on one thing at a time?
I'd like to be able to tab to the QPushButton. So, turning off focus isn't what I want, because that stopped me from being able to tab into the button.
Here's an image of the problem:
And here's the code:
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
from PySide.QtCore import *
from PySide.QtGui import *
class UI(object):
def setupUi(self, SessionInfo):
SessionInfo.setWindowTitle("Session Info")
# SessionInfo.resize(313, 159)
self.sessionLabel = QLabel(SessionInfo)
self.sessionLabel.setText("Session information:")
self.sessionId = QLineEdit(SessionInfo)
self.presetsLabel = QLabel(SessionInfo)
self.presetsLabel.setText("Presets:")
self.presetsButton = QPushButton(SessionInfo)
self.presetsButton.setText("Choose presets file")
self.saveButton = QPushButton(SessionInfo)
self.saveButton.setText("Begin session")
self.saveButton.setFocusPolicy(Qt.StrongFocus)
spacerItem = QSpacerItem(40, 20,
QSizePolicy.Expanding,
QSizePolicy.Minimum)
self.gridLayout = QGridLayout(SessionInfo)
self.gridLayout.addWidget(self.sessionLabel, 0, 0, 1, 1)
self.gridLayout.addWidget(self.sessionId, 0, 1, 1, 2)
self.gridLayout.addWidget(self.presetsLabel, 1, 0, 1, 1)
self.gridLayout.addWidget(self.presetsButton, 1, 1, 1, 2)
self.gridLayout.addItem(spacerItem, 2, 0, 1, 2)
self.gridLayout.addWidget(self.saveButton, 2, 2, 1, 1)
def main():
import sys
app = QApplication(sys.argv)
Dialog = QDialog()
sessionInfo = UI()
sessionInfo.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
It seems you cannot use a QDialog for that because it always wants to have exactly one default button, even right from the beginning. QWidget instead is more nice but doesn't set the default property of its button when they get focus. However, you can do that by yourself overriding focusInEventand focusOutEvent in your custom buttons.
Example:
from PySide.QtGui import *
class FocusButton(QPushButton):
def __init__(self, *args, **kwargs):
QPushButton.__init__(self, *args, **kwargs)
def focusInEvent(self, event):
self.setDefault(True)
QPushButton.focusInEvent(self, event)
def focusOutEvent(self, event):
self.setDefault(False)
QPushButton.focusOutEvent(self, event)
app = QApplication([])
dlg = QWidget()
label1 = QLabel("Label one")
label2 = QLabel("Label two")
edit1 = QLineEdit(dlg)
button1 = FocusButton("Button one")
button2 = FocusButton("Button two")
spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
gridLayout = QGridLayout(dlg)
gridLayout.addWidget(label1, 0, 0, 1, 1)
gridLayout.addWidget(edit1, 0, 1, 1, 2)
gridLayout.addWidget(label2, 1, 0, 1, 1)
gridLayout.addWidget(button1, 1, 1, 1, 2)
gridLayout.addItem(spacerItem, 2, 0, 1, 2)
gridLayout.addWidget(button2, 2, 2, 1, 1)
dlg.show()
app.exec_()
And the buttons are not highlighted initially, only if they get the focus.
I am trying to create a simple application with PySide, but it seems that I didn't read the docs properly. That is my code:
from PySide.QtGui import *
from PySide.QtCore import Qt
class Window(QMainWindow):
def __init__(self, parent = None):
QMainWindow.__init__(self, parent)
self.scene = QGraphicsScene()
self.view1 = QGraphicsView(self.scene, self)
self.view2 = QGraphicsView(self.scene, self)
self.gridLayout = QGridLayout()
self.gridLayout.addWidget(self.view1, 0, 0, Qt.AlignLeft)
self.gridLayout.addWidget(self.view2, 0, 1, Qt.AlignRight)
self.gridLayout.setColumnMinimumWidth(0, 300)
self.gridLayout.setColumnMinimumWidth(1, 300)
self.setLayout(self.gridLayout)
self.view1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.view2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.scene.addLine(0, 0, 1000, 1000)
if __name__ == "__main__":
app = QApplication(())
window = Window()
window.showMaximized()
app.exec_()
The code executes, but it should display a window with two QGraphicsViews, which should divide the window in half, but I only get one QGraphicsView in its minimum size. Can someone help me with this?
Thanks in advance.
You need to create a central widget for a QMainWindow, and then set the layout on that. Simplifying your example:
from PySide.QtGui import *
class Window(QMainWindow):
def __init__(self, parent = None):
QMainWindow.__init__(self, parent)
self.scene = QGraphicsScene()
self.view1 = QGraphicsView(self.scene, self)
self.view2 = QGraphicsView(self.scene, self)
self.view1.setFrameShape(QFrame.NoFrame)
self.view2.setFrameShape(QFrame.NoFrame)
widget = QWidget(self)
layout = QGridLayout(widget)
layout.addWidget(self.view1, 0, 0)
layout.addWidget(self.view2, 0, 1)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
self.setCentralWidget(widget)
self.scene.addLine(0, 0, 1000, 1000)
if __name__ == "__main__":
app = QApplication(())
window = Window()
window.showMaximized()
app.exec_()