Disable specific keyboard event of qslider - python

I am using qslider in python 3. I can move cursor forward and backward by keyboard event of up, down, left and right arrow. I would like to disable specifically part of them: up and down arrow move cursor while right and left cursor do not. Is it possible to do that?

You have to override the keyPressEvent method:
from PyQt5 import QtCore, QtGui, QtWidgets
class Slider(QtWidgets.QSlider):
def keyPressEvent(self, event):
if event.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Right):
return
super(Slider, self).keyPressEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
lay = QtWidgets.QHBoxLayout(w)
slider = Slider()
label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
slider.valueChanged.connect(label.setNum)
label.setNum(slider.value())
lay.addWidget(slider)
lay.addWidget(label)
w.resize(160, 240)
w.show()
sys.exit(app.exec_())

Related

QComboBox click triggers a leaveEvent on the main QDialog

I am trying to build a hover Dialog but i am stuck at the interaction between QComboBox selection and QDialog's leaveEvent. it looks like when i try to click on combobox to select something, it triggers a leaveEvent which then hides my QDialog. Why is this happening? What can i try to ensure that the Dialog is only hidden when I move my mouse outside of the Dialog?
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
class hoverDialog(QDialog):
def __init__(self, parent=None):
super().__init__()
self.setAttribute(Qt.WA_DeleteOnClose)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.v = QVBoxLayout()
self.combobox = QComboBox()
self.combobox.addItems(['Work-around','Permanent'])
self.textedit = QPlainTextEdit()
self.v.addWidget(self.combobox)
self.v.addWidget(self.textedit)
self.setLayout(self.v)
#self.setMouseTracking(True)
def leaveEvent(self, event):
self.hide()
return super().leaveEvent(event)
class Table(QWidget):
def __init__(self, parent=None):
super().__init__()
self.label4 = QLabel()
self.label4.setText("hover popup")
self.label4.installEventFilter(self)
self.checkbox1 = QCheckBox()
self.pushButton3 = QPushButton()
self.pushButton3.setText('Generate')
self.pushButton3.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
self.pushButton3.clicked.connect(self.buttonPressed)
self.hbox5 = QHBoxLayout()
self.hbox5.addWidget(self.checkbox1)
self.hbox5.addWidget(self.label4)
self.hbox5.addWidget(self.pushButton3)
self.vbox1 = QVBoxLayout()
self.vbox1.addLayout(self.hbox5)
self.setLayout(self.vbox1)
self.autoResolve = hoverDialog(self)
def eventFilter(self, obj, event):
if obj == self.label4 and event.type() == QtCore.QEvent.Enter and self.autoResolve.isHidden():
self.onHovered()
return super().eventFilter(obj, event)
def onHovered(self):
pos = QtGui.QCursor.pos()
self.autoResolve.move(pos)
self.autoResolve.show()
def buttonPressed(self):
if self.checkbox.isChecked():
print('do something..')
if __name__ == '__main__':
app = QApplication(sys.argv)
form = Table()
form.show()
app.exec_()
Looking at the sources, I believe that the origin of the problem is in Qt's behavior whenever a new popup widget is shown.
I cannot guarantee this at 100%, but in any case the simplest solution is to hide the widget only if the combo popup is not shown:
def leaveEvent(self, event):
if not self.combobox.view().isVisible():
self.hide()
Note that your approach is not really perfect: since the dialog could be shown with a geometry that is outside the current mouse position, it will not be able to hide itself until the mouse actually enters it. You should probably filter FocusOut and WindowDeactivate events also.

QCalendarWidget on year click using pyqt5

How to fire mouse click event on clicking in year option for QCalendarWidget.
onclick of year(2012),
i want to print some text using pyqt5
Can anyone help. Thanks in advance/
The first thing is to obtain the QSpinBox that shows the year using findChildren, then it is to detect the mouse event but as this solution points out it is not possible so a workaround is to detect the focus event:
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.calendar_widget = QtWidgets.QCalendarWidget()
self.setCentralWidget(self.calendar_widget)
self.year_spinbox = self.calendar_widget.findChild(
QtWidgets.QSpinBox, "qt_calendar_yearedit"
)
self.year_spinbox.installEventFilter(self)
def eventFilter(self, obj, event):
if obj is self.year_spinbox and event.type() == QtCore.QEvent.FocusIn:
print(self.year_spinbox.value())
return super().eventFilter(obj, event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

How to make my title less Window drag-able in PyQt5?

I want to build a window which has no title bar, so i do. But it is not any more draggable. You cannot make my window move from here to there.
I know it is because of me, removing the title bar, but how to fix it?
This is my code:
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QWidget
import sys
def window():
app = QApplication(sys.argv)
win = QMainWindow()
win.setGeometry(300, 300, 300, 300)
win.setWindowTitle("Test")
win.setWindowFlags(QtCore.Qt.FramelessWindowHint)
label = QLabel(win)
label.setText("Hello world")
win.show()
sys.exit(app.exec_())
window()
Any help will be appreciated. Please help me with this...
You need to reimplement the mousePress and mouseMove methods of the widget (mouseRelease is technically not mandatory, but is actually required for consistency, as the release event has to be correctly intercepted by Qt to avoid any confusion). The former will get the current cursor position relative to the geometry (self.offset), while the latter will compute the new "window" position by adding the new position to the current one and subtracting the offset.
I would also suggest you to use a QWidget instead of a QMainWindow. While QMainWindow implementation is very similar to that of QWidgets, subclassing a QMainWindow for your purpose might be a bit harder, as it's widget more complex than it seems.
If you only need a QMainWindow to get a status bar, just add a new one to the widget layout; if you also need a menubar, add it to the widget's layout using setMenuBar.
class FramelessWidget(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Test")
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.label = QLabel("Hello world", self)
self.offset = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.offset = event.pos()
else:
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.offset is not None and event.buttons() == QtCore.Qt.LeftButton:
self.move(self.pos() + event.pos() - self.offset)
else:
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.offset = None
super().mouseReleaseEvent(event)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = FramelessWidget()
win.setGeometry(300, 300, 300, 300)
win.show()
sys.exit(app.exec_())

Keep QToolbar showing always all items

lets consider the following screenshot:
You can see that the top toolbar displays 2 rows; however to do so , in need to click on the >> at the top right (circled in red) and keep hovering hover the toolbar area, which can get a bit annoying.
Is there a way to keep the 2 rows of the toolbar always displaying?
The solution is:
Expand the QToolBar using the layout that in the implementation of the private API has a slot called setExpanded() that allows to expand the QToolBar.
Hide the button, and for this case it only worked to set the size to QSize(0, 0).
Deactivate the event Leave of the QToolBar so that it does not collapse.
from PyQt5 import QtCore, QtGui, QtWidgets
class ToolBar(QtWidgets.QToolBar):
def __init__(self, parent=None):
super().__init__(parent)
lay = self.findChild(QtWidgets.QLayout)
if lay is not None:
lay.setExpanded(True)
QtCore.QTimer.singleShot(0, self.on_timeout)
#QtCore.pyqtSlot()
def on_timeout(self):
button = self.findChild(QtWidgets.QToolButton, "qt_toolbar_ext_button")
if button is not None:
button.setFixedSize(0, 0)
def event(self, e):
if e.type() == QtCore.QEvent.Leave:
return True
return super().event(e)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QMainWindow()
toolbar = ToolBar()
for i in range(20):
toolbar.addAction("action{}".format(i))
w.addToolBar(QtCore.Qt.TopToolBarArea, toolbar)
w.resize(640, 480)
w.show()
sys.exit(app.exec_())

How to make QSlider unclickable

I'm creating a GUI where I have a few sliders. I want each QSlider such that it can only be dragged. Sometimes, if I click on any part of a QSlider, the position of the slider changes. How can I stop that from happening?
The solution is to verify that when you do not press with the mouse in the slider groove:
from PyQt5 import QtCore, QtWidgets
class SliderUnclickable(QtWidgets.QSlider):
def mousePressEvent(self, event):
opt = QtWidgets.QStyleOptionSlider()
self.initStyleOption(opt)
pressedControl = self.style().hitTestComplexControl(QtWidgets.QStyle.CC_Slider, opt, event.pos(), self)
if pressedControl != QtWidgets.QStyle.SC_SliderGroove:
super(SliderUnclickable, self).mousePressEvent(event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
flay = QtWidgets.QFormLayout(w)
w1 = QtWidgets.QSlider(QtCore.Qt.Horizontal)
w2 = SliderUnclickable(QtCore.Qt.Horizontal)
flay.addRow("default QSlider: ", w1)
flay.addRow("SliderUnclickable: ", w2)
w.show()
sys.exit(app.exec_())

Categories