I have some embedded QComboBox in a QTableView. To make them show by default I made those indexes "persistent editor". But now every time I do a mouse scroll on top them they break my current table selection.
So basically how can I disable mouse scrolling of QComboBox?
As I found this question, when I tried to figure out the solution to (basically) the same issue: In my case I wanted to have a QComboBox in a QScrollArea in pyside (python QT lib).
Here my redefined QComboBox class:
#this combo box scrolls only if opend before.
#if the mouse is over the combobox and the mousewheel is turned,
# the mousewheel event of the scrollWidget is triggered
class MyQComboBox(QtGui.QComboBox):
def __init__(self, scrollWidget=None, *args, **kwargs):
super(MyQComboBox, self).__init__(*args, **kwargs)
self.scrollWidget=scrollWidget
self.setFocusPolicy(QtCore.Qt.StrongFocus)
def wheelEvent(self, *args, **kwargs):
if self.hasFocus():
return QtGui.QComboBox.wheelEvent(self, *args, **kwargs)
else:
return self.scrollWidget.wheelEvent(*args, **kwargs)
which is callable in this way:
self.scrollArea = QtGui.QScrollArea(self)
self.frmScroll = QtGui.QFrame(self.scrollArea)
cmbOption = MyQComboBox(self.frmScroll)
It is basically emkey08's answer in the link Ralph Tandetzky pointed out, but this time in python.
The same can happen to you in a QSpinBox or QDoubleSpinBox. On QSpinBox inside a QScrollArea: How to prevent Spin Box from stealing focus when scrolling? you can find a really good and well explained solution to the problem with code snippets.
You should be able to disable mouse wheel scroll by installing eventFilter on your QComboBox and ignore the events generated by mouse wheel, or subclass QComboBox and redefine wheelEvent to do nothing.
c++ version of Markus ansver
class FocusWhellComboBox : public QComboBox
{
public:
explicit FocusWhellComboBox(QWidget* parent = nullptr)
: QComboBox(parent)
{
this->setFocusPolicy(Qt::StrongFocus);
}
void wheelEvent(QWheelEvent* e) override
{
if (this->hasFocus()) {
QComboBox::wheelEvent(e);
}
}
};
Related
Edit: this issue seems to be specific to Qt version 5.12.0. See the answers for more details and for a workaround
I'm trying to implement a drop zone for loading files into my application.
It works when I just show the widget as a top level widget, but it stops working as soon as I include it into another parent widget.
The problem is, altough I'm receiving dragEnterEvent and accepting it, I never see the dropEvent.
This is my widget:
class FileDropZone(qt.QLabel):
"""Target area for a drag and drop operation"""
height = 33
def __init__(self, text="Add file", parent=None):
super().__init__(text, parent)
stylesheet = """
QLabel {
border: 2px dotted #B4BDBA;
qproperty-alignment: AlignCenter;
}
"""
self.setStyleSheet(stylesheet)
self.setAcceptDrops(True)
self.setFixedHeight(self.height)
def dragEnterEvent(self, event):
print("in drag enter event")
if event.mimeData().hasUrls():
print("hasUrls()")
event.acceptProposedAction()
def dropEvent(self, event):
print("in drop event")
urls = event.mimeData().urls()
for url in urls:
print(url.isLocalFile(), url.toLocalFile())
This is how I manage to make it work:
app = qt.QApplication([])
a = FileDropZone()
a.show()
app.exec_()
And this is the example where it does not work (dragEnter works, both prints are properly printed, but dropEvent does not print anything):
app = qt.QApplication([])
a0 = qt.QWidget()
l = qt.QHBoxLayout(a0)
a1 = FileDropZone("drop here", a0)
l.addWidget(a1)
a0.show()
app.exec_()
Any clues about what is broken? Does the parent need to forward the event, and if so, how should I implement it?
It looks like it is a bug which was introduced in Qt 5.12.0 and will be fixed in Qt 5.12.1, see this discussion and this bug report.
In the meantime:
The problem can be worked around by reimplementing dragMoveEvent() and accepting the event there too.
i.e. add e.g. the following method to the FileDropZone class:
def dragMoveEvent(self, event):
print("in drag move event")
if event.mimeData().hasUrls():
print("hasUrls()")
event.acceptProposedAction()
I have a QDialog(QVBoxLayout) with the following widgets in order: QTextEdit, QLabel, [layout stretch], QPushButton
The problem is that I would like the QTextEdit to expand with the QDialog, but only until the scrollbar disappears, after which the layout stretch should start expanding, revealing a gap between the QLabel and the QPushButton.
What would be a sensible way to go about this?
Note: The QDialog is resizable and the QTextEdit has word wrapping on.
Edit: For Qt4/PySide, the following should work
class TextEdit(qt.QTextEdit):
def __init__(self, *args, **kwargs):
qt.QTextEdit.__init__(self, *args, **kwargs)
self.document().modificationChanged.connect(self.updateMaxHeight)
def updateMaxHeight(self, *args):
self.setMaximumHeight(self.document().size().height())
def resizeEvent(self, e):
qt.QTextEdit.resizeEvent(self, e)
self.updateMaxHeight()
class MyDialog(qt.QDialog):
def __init__(self, *args, **kwargs):
qt.QDialog.__init__(self, *args, **kwargs)
self.setLayout(qt.QVBoxLayout())
self.textEdit = TextEdit('Example text')
self.layout().addWidget(self.textEdit, 1) #1 for resizable
self.layout().addWidget(qt.QLabel('Example label')
self.layout().addStretch()
self.layout().addWidget(qt.QPushButton('Example button')
This is more difficult than it seems:
class TextEdit : public QTextEdit
{
public:
TextEdit(QWidget *parent = nullptr)
: QTextEdit(parent)
{
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
connect(this, &TextEdit::textChanged, this, &TextEdit::updateGeometry);
}
QSize viewportSizeHint() const override
{
return document()->size().toSize();
}
};
The idea is to make the viewport size hint correspond to the size of the document and make the scroll area adjust to the size of the viewport. You also have to make sure the the layout gets notified when new lines are added to the document.
The final piece of the puzzle is to give your stretch item a bigger stretch factor so that it doesn't start sharing space with the editor:
layout->addStretch(1);
I am working on QT v5.2
I need to hide the blinking cursor (caret) of QLineEdit permanently.
But at the same time, I want the QLineEdit to be editable (so readOnly and/or setting editable false is not an option for me).
I am already changing the Background color of the QLineEdit when it is in focus, so I will know which QLineEdit widget is getting edited.
For my requirement, cursor (the blinking text cursor) display should not be there.
I have tried styleSheets, but I can't get the cursor hidden ( {color:transparent; text-shadow:0px 0px 0px black;} )
Can someone please let me know how can I achieve this?
There is no standard way to do that, but you can use setReadOnly method which hides the cursor. When you call this method it disables processing of keys so you'll need to force it.
Inherit from QLineEdit and reimplement keyPressEvent.
LineEdit::LineEdit(QWidget* parent)
: QLineEdit(parent)
{
setReadOnly(true);
}
void LineEdit::keyPressEvent(QKeyEvent* e)
{
setReadOnly(false);
__super::keyPressEvent(e);
setReadOnly(true);
}
As a workaround you can create a single line QTextEdit and set the width of the cursor to zero by setCursorWidth.
For a single line QTextEdit you should subclass QTextEdit and do the following:
Disable word wrap.
Disable the scroll bars (AlwaysOff).
setTabChangesFocus(true).
Set the sizePolicy to (QSizePolicy::Expanding, QSizePolicy::Fixed)
Reimplement keyPressEvent() to ignore the event when Enter/Return is hit
Reimplement sizeHint to return size depending on the font.
The implementation is :
#include <QTextEdit>
#include <QKeyEvent>
#include <QStyleOption>
#include <QApplication>
class TextEdit : public QTextEdit
{
public:
TextEdit()
{
setTabChangesFocus(true);
setWordWrapMode(QTextOption::NoWrap);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setFixedHeight(sizeHint().height());
}
void keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
event->ignore();
else
QTextEdit::keyPressEvent(event);
}
QSize sizeHint() const
{
QFontMetrics fm(font());
int h = qMax(fm.height(), 14) + 4;
int w = fm.width(QLatin1Char('x')) * 17 + 4;
QStyleOptionFrameV2 opt;
opt.initFrom(this);
return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
expandedTo(QApplication::globalStrut()), this));
}
};
Now you can create an instance of TextEdit and set the cursor width to zero :
textEdit->setCursorWidth(0);
Most straight forward thing I found was stolen from this github repo:
https://github.com/igogo/qt5noblink/blob/master/qt5noblink.cpp
Basically you just want to disable the internal "blink timer" Qt thinks is somehow good UX (hint blinking cursors never were good UX and never will be - maybe try color or highlighting there eh design peeps).
So the code is pretty simple:
from PyQt5 import QtGui
app = QtGui.QApplication.instance()
app.setCursorFlashTime(0)
voilĂ .
Solution in python:
# somelibraries
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.setFocus() # this is what you need!!!
container = QWidget()
container.setLayout(self.layout)
# Set the central widget of the Window.
self.setCentralWidget(container)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
I ran into the same problem but setReadOnly is not a viable option because it alters the UI behavior in other places too.
Somewhere in a Qt-forum I found the following solution that actually solves the problem exactly where it occurs without having impact on other parts.
In the first step you need to derive from QProxyStyle and overwrite the pixelMetric member function:
class CustomLineEditProxyStyle : public QProxyStyle
{
public:
virtual int pixelMetric(PixelMetric metric, const QStyleOption* option = 0, const QWidget* widget = 0) const
{
if (metric == QStyle::PM_TextCursorWidth)
return 0;
return QProxyStyle::pixelMetric(metric, option, widget);
}
};
The custom function simply handles QStyle::PM_TextCursorWidth and forwards otherwise.
In your custom LineEdit class constructor you can then use the new Style like this:
m_pCustomLineEditStyle = new CustomLineEditProxyStyle();
setStyle(m_pCustomLineEditStyle);
And don't forget to delete it in the destructor since the ownership of the style is not transferred (see documentation). You can, of course, hand the style form outside to your LineEdit instance if you wish.
Don't get complicated:
In QtDesigner ,
1.Go the the lineEdit 's property tab
2.Change focusPolicy to ClickFocus
That's it...
Recently, I want that QListWidgetItem can emit a signal, when the mouse pointer enter. Show a QStackedWidget, when leave, hide the QStackedWidget;
I defined a class My_ListWidget; in the class i override enterEvent and leaveEvent. But this is i hover the QListWidget not the QListWidgetItem, and it always show the first of the QStackedWidget.
override mouseMoveEvent and grab the QListWidgetItem under the cursor with itemAt(event.pos())
edit: instead of overriding mouseEvent you can use the signal entered which will also pass the ModelIndex of the item end then use leaveEvent to clear the stacked widget, you need to activate mouseTracking for this to work
For me, I had some problems with getting the Item via itemAt. When subclassing QListWidget, you can enable mouse tracking with setMouseTracking(True) and use itemEntered and leaveEvent
class My_ListWidgetClass(QListWidget):
def __init__(self):
QListWidget.__init__(self)
self.setMouseTracking(True)
class Main(...):
def __init__(self):
self.centralWidget.connect( self.My_ListWidgetInstance,
SIGNAL('itemEntered(QListWidgetItem *)'),
self.whenItemEntered_doThis)
self.centralWidget.connect( self.My_ListWidgetInstance,
SIGNAL('leaveEvent(QEvent *)'),
self.whenItemLeft_doThis)
def whenItemEntered_doThis(self, QLWItem):
# you can apply behavior here according
# to the QListWidgetItem given as argument
# e. g. get itemtext (itemtext = str(QLWItem.text())
def whenItemLeft_doThis(self, Event):
# executed when an item was left
# unfortunatelly I can't explain, what you
# can do with the event. I didn't need it...
Neither I could find a tutorial-like scheme for a resize event on QMainWindow, nor I did see any option for adding resize event in the drop-down menu at the Qt design window.
I am new to Qt. I'd like to write a slot function for a QMainWindow resize event. Is there such event? How can I do this?
There is a resize event. In order to perform custom handling of the event, you'll need to create your own resize event handler. In your case, you would need to create a class that derives from QMainWindow and reimplement the resizeEvent function. Your code would look something like this:
void MyMainWindow::resizeEvent(QResizeEvent* event)
{
QMainWindow::resizeEvent(event);
// Your code here.
}
The Qt Scribble example also has an example of overriding the resize event (though not on the main window).
This works in Qt5 with me f.e. to resize the icon in a QTableWidget:
mainWindow.h
...
private:
void resizeEvent(QResizeEvent*);
...
mainWindow.cpp
...
void mainWindow::resizeEvent(QResizeEvent*)
{
tableWidget->setIconSize(QSize(tableWidget->size()/7)); //7 or whatever number you need it to get the full icon size
}
In PyQt5 try the following:
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
class MainWindow(qtw.QMainWindow):
def __init__(self):
super().__init__()
self.resize(600, 600)
# your code
def resizeEvent(self, e: qtg.QResizeEvent):
# your code