How to reposition cursor to the end of the document without autoscroll
-
@lukutis222 said in How to reposition cursor to the end of the document without autoscroll:
I was wondering if I need to create a seperate class just for QTextEdit so I can override one function?
Yes, this is how subclassing and overriding works.
"Can I make widget class inherit from QTextEdit and then override it in my widget class if that makes sense?" - not sure what you mean. As I sais: subclass QTextEdit and override in your subclass...
And please also read what @JonB suggested.
-
@JonB said in How to reposition cursor to the end of the document without autoscroll:
Look at installing an application event filter, or on your
Widget
, for a convenient way of intercepting all mouse events, regardless of targeted widget: https://doc.qt.io/qt-6/eventsandfilters.html, https://doc.qt.io/qt-6/qobject.html#eventFilter. Otherwsie you will have to subclass and overridemousePressEvent
for every one of your widgets.Should be pretty clear. Or you can ignore it.
-
@jsulm @JonB
JonB I do not ignore and I will definately look into this (eventfilters). I just want to learn first how to correctly override subclass methods because this is very interesting topic for me and very useful to learn. I am still learning C++ and I feel like this is very important to understand (which I struggle to do yet)Just for the sake of testing, I have created a class with a QTextEdit base class:
custom_text_edit.cpp
#include "custom_text_edit.h" custom_text_Edit::custom_text_Edit() { } void custom_text_Edit::mousePressEvent(QMouseEvent *event) { qDebug("pressed inside qtextedit \n"); }
custom_text_edit.h
#ifndef CUSTOM_TEXT_EDIT_H #define CUSTOM_TEXT_EDIT_H #include <QTextEdit> class custom_text_Edit : public QTextEdit { public: custom_text_Edit(); protected: void mousePressEvent(QMouseEvent *event) override; }; #endif // CUSTOM_TEXT_EDIT_H
I create class instance in my main.cpp:
custom_text_Edit cte;
Is there anything else I am missing? When I click on the QTextEdit widget ( my console), I still cannot trigger the mouseclick event that I just overriden
-
@lukutis222 said in How to reposition cursor to the end of the document without autoscroll:
Is there anything else I am missing?
Yes, you are still using QTextEdit in your UI. You need to replace it with your custom_text_Edit.
-
@lukutis222
Are you 100% sure you have changed yourQTextEdit
, designed in Qt Designer, over to this newcustom_text_Edit
? How did you manage that (without promoting)?Which is one reason this subclassing instead of
eventFilter()
is going to be a pain for you.... Event filter allows you to intercept events without having to subclass, which I believe is what you requested/would like. -
-
@lukutis222
Note that Qt has two means of "notifying" that something has happened. Events are just protected methods and require subclassing if you need to know about them . Signals on the other hand are public methods and you can attach slots to be notified of their occurrence without needing to subclass. (Note also that in an event you can alter the behaviour of the handling of the event, if you wish to, but in a signal you cannot, the action has already happened and you can only add your own behaviour not alter the action's existing behaviour.) For example, mouse up/down are events, but "click" is a signal; same for key presses as opposed to, say, thetextChanged()
signal after a down/up. Nobody knows the official definition/determination of when an action is exposed as a signal rather than an event, but basically the lowest level activities are events and higher level ones are signals.eventFilter()
is neither an event nor a signal. It is a method you can install as a "hook" for any low level event which may arise, allowing you either to just monitor it (as in your case) or alter what happens to it before further Qt processing. It conveniently allows any event to any widget to be intercepted without needing to subclass. -
@JonB Thank you very much for all this useful information. After reading a little about bit about the eventfilters and looking at some examples (https://forum.qt.io/topic/110350/how-to-make-an-eventfilter/2), I have changed my implemented eventfilter in my widget component.
In my widget.cpp, I have added:
bool Widget::eventFilter(QObject *object, QEvent *event) { //qDebug("event filter \n"); if ((object == ui->Console_read) && (event->type() == QEvent::MouseButtonPress) ) { qDebug("mouse clicked \n"); } if ( object == ui->Console_read && ( event->type() == QEvent::MouseButtonDblClick ) ) { qDebug("mouse double click \n"); } return false; }
And in the widget constructor:
ui->Console_read->installEventFilter(this); // console read is the QTextEdit window that I would like to detect mouse clicks on
in my widget.h
I have added function prototype under the private section:private: Ui::Widget *ui; bool eventFilter(QObject *object, QEvent *event);
However, it does not seem to work as I expected. I was expecting the below to be triggered when I click anywhere on the console
if ((object == ui->Console_read) && (event->type() == QEvent::MouseButtonPress) ) { qDebug("mouse clicked \n"); }
and below to be triggered when I double click anywhere on the console.
if ( object == ui->Console_read && ( event->type() == QEvent::MouseButtonDblClick ) ) { qDebug("mouse double click \n"); }
However, the event filter does not react to the left mouse button click and double left mouse button click.
When I right click mouse button, the event filter triggers MouseButtonPress. Why would it react to right click for MouseButtonPress Is that default? Do I need to override the MouseButtonPress?
-
@lukutis222 Print out what event->type() returns in your eventFilter and see what you get when you press left mouse button. For left mouse button click you should get two events: QEvent::MouseButtonPress and QEvent::MouseButtonRelease.
-
@lukutis222
I don't know why you are not getting the left mouse button, especially as you say you do for the right button. Like @jsulm I would expect a mouse press and a mouse release. Start by removing yourobject == ui->Console_read &&
, let's see whether you get these anywhere regardless of object? Also do as @jsulm says: log every event arriving in youreventFilter()
, see if there is anything else there of interest. -
@jsulm said in How to reposition cursor to the end of the document without autoscroll:
Print out what event->type(
When I hover my mouse over console, events 10 and 110 are generated
When cursor leaves the console area, event 11 is generated
When I left click on my console, event = 207 is generated.
When I click left mouse button multiple times(double click), multiple 207 events are generated:
event->type() = 207 event->type() = 207 event->type() = 207 event->type() = 207
Right mouse button click generates 4 events:
event->type() = 2 mouse clicked event->type() = 9 event->type() = 12 event->type() = 11
bool Widget::eventFilter(QObject *object, QEvent *event) { qDebug("event->type() = %u \n",event->type()); if ((object == ui->Console_read) && (event->type() == QEvent::MouseButtonPress) ) { qDebug("mouse clicked \n"); } if ( object == ui->Console_read && ( event->type() == QEvent::MouseButtonDblClick ) ) { qDebug("mouse double click \n"); } return false; }
Additionally, I tried to remove object == ui->Console_read but does not have any different affect
-
@lukutis222
If you wait a few minutes I will knock up a tiny sample (I am Linux and Qt5,15, you never seem to have said what you are) with aQTextEdit
and see whether I get the left mouse button press/release.... Come back and look in a while :) -
@lukutis222
Please note that tells you your Creator was built with Qt 6.3.1, but not what version of Qt you downloaded and use for you application. Anyway at a guess it's some Qt 6. Whatever, my test will be Linux + Qt 5.15, you will have to see how that behaves for you. -
@JonB
Based on my directory folders I assume the project is also 6_3_1:
Anyways, in my application, apart from the Console I have a write box where user can write commands to the serial device:
Just for testing purpose, I have created eventfilter2 for QLineEdit events and I can see that it behaves differently than QTextEdit:
When I left click mouse button on the small rectangular text box at the bottom of my application, many events are generated(Just from one left mouse button click):event->type() = 213 event->type() = 71 event->type() = 12 event->type() = 170 event->type() = 170 event->type() = 110 event->type() = 207 event->type() = 8 event->type() = 207 event->type() = 207 event->type() = 207 event->type() = 2 mouse clicked event->type() = 207 event->type() = 207 event->type() = 12 event->type() = 170 event->type() = 170 event->type() = 170 event->type() = 3 event->type() = 207 event->type() = 12 event->type() = 170 event->type() = 170 event->type() = 12 event->type() = 170 event->type() = 170 event->type() = 12 event->type() = 170 event->type() = 170 event->type() = 12 event->type() = 170 event->type() = 170 event->type() = 12 event->type() = 170 event->type() = 170 event->type() = 12 event->type() = 170 event->type() = 170
As you can see from above, one of the events were triggered mouse clicked so that seem to work (Im not sure why it is creating so many 12 170 170 events over and over again )
-
@lukutis222
OK, it gets complicated. Full story probably in https://stackoverflow.com/questions/41631011/my-qt-eventfilter-doesnt-stop-events-as-it-should. I agreeQTextEdit
behaves differently fromQLineEdit
. I said you may needLook at installing an application event filter
and you do.
Here is my sample application:
#include <QCoreApplication> #include <QDebug> #include <QLineEdit> #include <QTextEdit> #include <QVBoxLayout> #include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vlayout = new QVBoxLayout; QLineEdit *lineEdit = new QLineEdit; lineEdit->setObjectName("lineEdit"); vlayout->addWidget(lineEdit); QTextEdit *textEdit = new QTextEdit; textEdit->setObjectName("textEdit"); vlayout->addWidget(textEdit); setLayout(vlayout); QCoreApplication::instance()->installEventFilter(this); lineEdit->installEventFilter(this); textEdit->installEventFilter(this); } Widget::~Widget() { } bool Widget::eventFilter(QObject *obj, QEvent *event) { // qDebug() << event->type(); if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) qDebug() << "Mouse button event" << obj->objectName() << event->type(); // pass the event on to the parent class return QWidget::eventFilter(obj, event); }
Note how I use
QCoreApplication::instance()->installEventFilter(this);
.Output (from left-clicking in each of the line edit and text edit) is:
11:17:36: Debugging starts Mouse button event "WidgetClassWindow" QEvent::MouseButtonPress Mouse button event "lineEdit" QEvent::MouseButtonPress Mouse button event "lineEdit" QEvent::MouseButtonPress Mouse button event "WidgetClassWindow" QEvent::MouseButtonRelease Mouse button event "lineEdit" QEvent::MouseButtonRelease Mouse button event "lineEdit" QEvent::MouseButtonRelease Mouse button event "WidgetClassWindow" QEvent::MouseButtonPress Mouse button event "qt_scrollarea_viewport" QEvent::MouseButtonPress Mouse button event "WidgetClassWindow" QEvent::MouseButtonRelease Mouse button event "qt_scrollarea_viewport" QEvent::MouseButtonRelease 11:17:41: Debugging has finished
See how for the
QTextEdit
the mouse events actually go toqt_scrollarea_viewport
.I leave you to play with this/adapt to your needs.
-
@lukutis222
"Yes I figured that but its not fully clear how to do it since I do not have a seperate class for QTextEdit. Can I do that in my Widget component?"slot function:
QObject* objTE1 = QObject::sender(); if (objTE1 == textEdit) { // you can catch the click or press event here. you should declare textEdit public to access. <do action on mouse press or click event here> }
you can use to catch the click or mouse press event here by connecting the signal (click or press) of the textEdit obj to any defined slot above. this way you can always catch the specific child Widget
-
@dan1973 I am now able to check in mouse click event the position of the cursor but I am not sure how is it indended to help me:
bool Widget::eventFilter(QObject *object, QEvent *event) { if ( event->type() == QEvent::MouseButtonPress) { qDebug("mouse click event \n"); QString str1 = "\n X:"+QString::number(QCursor::pos().x())+ "Y:" +QString::number(QCursor::pos().x()); qDebug("str1 = %s\n",str1.toStdString().c_str()); } if ( object == ui->Console_read && ( event->type() == QEvent::MouseMove ) ) { qDebug("mouse move event \n"); QString str1 = "\n X:"+QString::number(QCursor::pos().x())+ "Y:" +QString::number(QCursor::pos().x()); qDebug("str1 = %s\n",str1.toStdString().c_str()); } return false; }