I'm trying to make a button (or any other Qwidget), That will change users cursor when hovered.
So for instance, when i hover QPushButton, it will change cursor from Arrow to Pointing Hand.
I am using Qt Style Sheet, so i'm not entirely sure, but is there any way to do something like that there?, should look something like this:
btn.setStyleSheet("#btn {background-image: url(':/images/Button1.png'); border: none; }"
"#btn:hover { change-cursor: cursor('PointingHand'); }
Note: Code above is for example, second line will have no functionality at all.
However, if not, if there any other way i can achieve this?
For anyone who wants to achieve this in PyQt5, this is how I managed to do it. Let's say you have a button and you want your cursor to change to the 'PointingHandCursor' when you hover over the button.
You can do it with your_button.setCursor(QCursor(QtCore.Qt.PointingHandCursor)). For example:
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QLabel, QProgressBar,
QLineEdit, QFileDialog
from PyQt5 import QtGui, QtCore
from PyQt5.QtGui import QCursor
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.title = "your_title"
self.screen_dim = (1600, 900)
self.width = 650
self.height = 400
self.left = int(self.screen_dim[0]/2 - self.width/2)
self.top = int(self.screen_dim[1]/2 - self.height/2)
self.init_window()
def init_window(self):
self.setWindowIcon(QtGui.QIcon('path_to_icon.png'))
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.setStyleSheet('background-color: rgb(52, 50, 51);')
self.create_layout()
self.show()
def create_layout(self):
self.button = QPushButton('Click Me', self)
self.button.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
if __name__ == '__main__':
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
Use QWidget.setCursor (self, QCursor)
http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#setCursor
http://doc.qt.io/qt-4.8/qwidget.html#cursor-prop
For Pyqt6 you can use this code:
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QCursor
closeBtn = QPushButton("X")
closeBtn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
Related
The window shows a set of pictures. Once the window is maximized the app shows all pics in the window so it resizes every image looking ugly. I'd like to prevent the streching and keep the aspect ratio. Any clue?
This is the code of the proof of concept:
QApplication, QListWidget, QAbstractItemView, QPushButton, QWidget,
QTabWidget, QVBoxLayout, QHBoxLayout, QLabel, QPlainTextEdit,
QTextEdit, QCheckBox, QFileDialog, QMessageBox, QGridLayout from
PyQt5.QtCore import QProcess, QTimer, Qt from PyQt5.QtGui import QFont, QPixmap import os from QLabelClickable import QLabelClickable
class ExampleApp(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'Example'
self.left = 0
self.top = 0
self.width = 1000
self.height = 800
self.setMaximumWidth(1000)
self.setMaximumHeight(800)
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.show()
data = []
for root, dirs, files in os.walk('img/'):
for file in files:
filepath = os.path.join(root, file)
data.append(filepath)
self.picture_window = PictureWindow(data=data)
self.picture_window.show()
class PictureWindow(QWidget):
def __init__(self, data):
super().__init__()
self.n_columns = 5
self.data = data
self.gridLayout = QGridLayout()
for i, filename in enumerate(self.data):
self.render_picture(filename=filename, pos=i)
self.setLayout(self.gridLayout)
def render_picture(self, filename, pos):
image_widget = QLabelClickable(pos)
image_widget.setGeometry(15, 15, 118, 130)
image_widget.setToolTip(filename)
image_widget.setCursor(Qt.PointingHandCursor)
self.pixmapImagen = QPixmap(filename).scaled(375, 375, Qt.KeepAspectRatio, Qt.SmoothTransformation)
image_widget.setPixmap(self.pixmapImagen)
image_widget.setAlignment(Qt.AlignCenter)
cell_layout = QVBoxLayout()
cell_layout.setAlignment(Qt.AlignHCenter)
cell_layout.addWidget(image_widget)
self.gridLayout.addLayout(cell_layout, int(pos / self.n_columns), pos % self.n_columns)
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QMessageBox
class QLabelClickable(QLabel):
clicked = pyqtSignal(str)
def __init__(self, id, parent=None):
super(QLabelClickable, self).__init__(parent)
self.id = id
def mousePressEvent(self, event):
self.ultimo = "Click"
def mouseReleaseEvent(self, event):
if self.ultimo == "Click":
QTimer.singleShot(QApplication.instance().doubleClickInterval(),
self.performSingleClickAction)
else:
self.clicked.emit(self.ultimo+"-"+str(self.id))
def mouseDoubleClickEvent(self, event):
self.ultimo = "Double Click"
def performSingleClickAction(self):
if self.ultimo == "Click":
self.clicked.emit(self.ultimo+"-"+str(self.id))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = ExampleApp()
sys.exit(app.exec_())
This is how it looks when window is normal:
And looks like this when window is maximized:
After a few days trying to figure out what's going on here I an't go further, could you please help me to spot anything wrong?
I expect the pics to keepe their aspect ratio to implement a ScrollArea later on.
I want to change the way my splitter handle looks in Pyqt5. In the code below, consider self.widg_1 and self.widg_2 to be any two widgets. Using setStyleSheet results in the error:
self.my_splitter_handle.setStyleSheet("border: 3px blue")
AttributeError: 'NoneType' object has no attribute 'setStyleSheet'
import sys
from PyQt5.QtCore import Qt
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication, QWidget, QFrame, QLineEdit, QHBoxLayout, QSplitter
class MyMainWindow(QWidget):
def __init__(self):
super().__init__()
self.title = "PyQt5 Splitter"
self.top = 200
self.left = 500
self.width = 400
self.height = 300
hbox = QHBoxLayout()
self.widg_1 = QFrame()
self.widg_1.setFrameShape(QFrame.StyledPanel)
self.my_splitter = QSplitter(Qt.Horizontal)
self.widg_2 = QLineEdit()
self.my_splitter.addWidget(self.widg_1)
self.my_splitter.addWidget(self.widg_2)
self.my_splitter.setSizes([200, 200])
hbox.addWidget(self.my_splitter)
# Note: splitter handle 0 is always hidden and handle 1 is between the widgets 1 & 2
self.my_splitter_handle = self.my_splitter.handle(1)
self.my_splitter_handle.setStyleSheet("background: 3px blue;")
self.setLayout(hbox)
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.show()
App = QApplication(sys.argv)
window = MyMainWindow()
sys.exit(App.exec())
Note: I just want a decent and prominent looking splitter handle with an arrow or some other marker like the one in the image.
I'm new to PyQt5 and Python, My question is how to enable the Horizontal scroll-bar if user enter more data in single line of the input box?
Currently it Input box enabling vertical scroll-bar if you enter more data.
can any one help me out how to enable both horizontal and Vertical scroll-bar if user enter more data?
Current Python Code:
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QFileDialog
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel
class MainWindow(QMainWindow, QWidget):
def __init__(self):
QMainWindow.__init__(self)
self.height = 480
self.width = 640
self.top = 10
self.left = 10
self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint)
self.setMinimumSize(QSize(800, 600))
self.setWindowTitle("My Windows")
# .... other Code here
# Edit Box
input_et_box = QFrame(self)
input_et_box.resize(300, 450)
input_et_box.move(50, 80)
layout = QHBoxLayout(input_et_box)
self.textEdit = QTextEdit(self)
layout.addWidget(self.textEdit)
# If we enter more data in Edit Box it will automatically enabled Vertical Scroll bar but Horizontal Scroll bar is not enabling automatically
# bar is not enabling
def printHello(self):
print("Hello")
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
layout = QGridLayout()
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())
Snapshot:
Use self.textEdit.setLineWrapMode(QTextEdit.FixedPixelWidth)
I made a view with QPlainTextEdit and set setLayoutDirection(QtCore.Qt.RightToLeft). The output of self.plaintxt.isRightToLeft()is 1 but in the plain text view, persian and english text are displayed from left. What is happen in my code?
Code:
import sys, re
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QLabel, QLineEdit, QMainWindow, QPushButton, QFileSystemModel, QTreeView, \
QFileDialog, QComboBox, QPlainTextEdit
from PyQt5.QtCore import pyqtSlot
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
self.title = 'by PyQt5 and python 3.7'
self.left = 10
self.top = 10
self.width = 1000
self.height = 500
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.btn_browse = QPushButton('Browse', self)
self.btn_browse.move(50, 20)
self.btn_browse.clicked.connect(self.on_click)
self.textbox = QLineEdit(self)
self.textbox.move(170, 20)
self.textbox.resize(280, 40)
self.textbox.setAlignment(QtCore.Qt.AlignRight) # It is in right.
self.page_view = QPlainTextEdit(self)
self.page_view.move(20, 100)
self.page_view.resize(800, 400)
self.page_view.setLayoutDirection(QtCore.Qt.RightToLeft) # It is not in right.
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
QWidget.setLayoutDirection no longer affects the text layout direction (Qt.LeftToRight or Qt.RightToLeft) of QTextEdit, QLineEdit and widgets based on them.
To programmatically force the text direction , you can change the defaultTextOption of the QTextDocument associated with that widget with a new QTextOption of different textDirection property.
QTextDocument *QPlainTextEdit::document() const
Returns a pointer to
the underlying document.
void QTextDocument::setDefaultTextOption(const QTextOption &option)
Sets the default text option to option.
self.page_view.document().setDefaultTextOption(QTextOption(Qt.AlignRight))
Don't use QPlainText, as it uses internally QPlainTextDocumentLayout which does not fully support RTL (automatic alignment for example - like you are looking for). You can use QTextEdit, or use a different document layout class (like QTextDocumentLayout) in your QPlainText.
The reason for those Plain classes exist, is to be faster by removing features... which you need.
I am new to GUI development and I am trying to learn how to use pyqt5 in python.
Below is the example code I am working on. I want a window with some checkboxes,combobox and radiobuttons on the right side of the window. The details of the QtWidget objects are in the code.
from PyQt5.QtWidgets import QApplication, QMainWindow, QSizePolicy, QWidget, QPushButton, QComboBox, QRadioButton, QVBoxLayout, QCheckBox
from PyQt5.QtGui import QIcon
class App(QMainWindow):
def __init__(self):
super().__init__()
self.left = 0
self.top = 500
self.title = 'Chip2 Torque Data'
self.width = 500
self.height =500
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
xselect=QRadioButton("X",self)
xselect.setChecked(True)
xselect.move(340,400)
zselect=QRadioButton("Z",self)
zselect.move(380,400)
sselect=QRadioButton("SP1",self)
sselect.move(420,400)
pass_list=QComboBox(self)
pass_list.addItems(sheets_idealcut)
pass_list.move(340,300)
rawdata_check=QCheckBox("Raw Data",self)
rawdata_check.setChecked(True)
rawdata_check.move(340,200)
mvgavg_check=QCheckBox("Moving average",self)
mvgavg_check.setChecked(True)
mvgavg_check.move(380,200)
mvgstd_check=QCheckBox("Moving stdev",self)
mvgstd_check.setChecked(True)
mvgstd_check.move(420,200)
self.show()
if __name__ == '__main__':
sheets_idealcut=['pass2','pass3','pass4','pass5']
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
else:
print('QApplication instance already exists: %s' % str(app))
ex = App()
#ex.show()
app.exec_()
Below is the output of the code. (Please ignore the overlapping checkbox names. I intend to correct it later.)
My problem is when I maximise this window, the QtWidget objects(QComboBox,QRadioButton,QCheckBox) don't readjust their position with the new window size.
So for the widgets to reposition themselves automatically, what method should be used ?
I googled it but I couldn't find anything useful.
Please help.
You are using move(x,y) which sets the Widgets to a specific fixed position. So you could write a function which is called on maximizing the window and then reposition your widgets accordingly.
Another automated approach is to use box layouts. QtGui.QHBoxLayout and QtGui.QVBoxLayout are basic layout classes which lines up widgets horizontally or vertically. From your pictures I do not know what exact positions you want your widgets to end up, so I try to explain it like I think you want it.
Each row of elements can be assigned into a HBox like this:
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(rawdata_check)
hbox.addWidget(mvgavg_check)
hbox.addWidget(mvgstd_check)
If you then resize the window the widgets should automaticly be repositioned to the right side of the window. The QtDesigner can help you arranging all the elements.
You should be using layouts for dynamic sizing. There are alot of different layouts. The layouts used in this example is the most basic types. I also changed the parent of "App" to a QDialog. They are easier to handle.
Here is an example of your app, using layouts:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QSizePolicy, QWidget, QPushButton, QComboBox, QRadioButton, \
QVBoxLayout, QCheckBox, QHBoxLayout, QGroupBox, QDialog
from PyQt5.QtGui import QIcon
class App(QDialog):
def __init__(self):
super().__init__()
self.left = 0
self.top = 500
self.title = 'Chip2 Torque Data'
self.width = 500
self.height = 500
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.main_layout = QVBoxLayout()
xselect=QRadioButton("X",self)
xselect.setChecked(True)
# xselect.move(340,400)
self.main_layout.addWidget(xselect)
zselect=QRadioButton("Z",self)
# zselect.move(380,400)
self.main_layout.addWidget(zselect)
sselect=QRadioButton("SP1",self)
# sselect.move(420,400)
self.main_layout.addWidget(sselect)
pass_list=QComboBox(self)
pass_list.addItems(sheets_idealcut)
self.main_layout.addWidget(pass_list)
#pass_list.move(340,300)
rawdata_check=QCheckBox("Raw Data",self)
rawdata_check.setChecked(True)
self.main_layout.addWidget(rawdata_check)
#rawdata_check.move(340,200)
mvgavg_check=QCheckBox("Moving average",self)
mvgavg_check.setChecked(True)
#mvgavg_check.move(380,200)
mvgstd_check=QCheckBox("Moving stdev",self)
mvgstd_check.setChecked(True)
#mvgstd_check.move(420,200)
self.check_group = QHBoxLayout()
self.check_group.addWidget(mvgavg_check)
self.check_group.addWidget(mvgstd_check)
self.check_group.stretch(1)
self.main_layout.addLayout(self.check_group)
self.setLayout(self.main_layout)
self.show()
if __name__ == '__main__':
sheets_idealcut=['pass2','pass3','pass4','pass5']
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
else:
print('QApplication instance already exists: %s' % str(app))
ex = App()
#ex.show()
app.exec_()