How to find global position of text cursor? - qt

I would like to execute a QMenu object at the position of text cursor in a QPlainTextEdit. My problem is that QTextCursor is only define by its position in the Text (index of the character).
How can I find global position of the QTextCursor? Should I use an other object than QTextCursor in order to find the position of the text cursor where I want to open my QMenu?
Thank you by advance.

I've never tried myself, but doesn't QPlainTextEdit::cursorRect() work? It should give you position of the cursor in viewport coordinates. You can then get the viewport using viewport() and map the local position to global using viewport()->mapToGlobal().

I have found similar query to your in some online forum and here's someone suggested the output as
Note: Reference from http://www.unix.com/unix-linux-applications/81388-read-position-mouse-cursor.html, Author of below posting is daggilli, registered user of UNIX online forums. Credit of below posting in its complete form goes to daggilli.
This is the complete code for a Qt application I threw together in about ten minutes (called crosshair) which displays the current mouse coordinates in a window. You might be able to pull enough out of it to be useful. This is Qt 3.1, but Qt 4 is not a great deal different. You will need the Qt development libraries, not just the runtimes. The code comprises two files, crosshair.h and crosshair.cpp.
crosshair.h:
Code:
#ifndef CROSSHAIR_H
#define CROSSHAIR_H
#include <qwidget.h>
#include <qstring.h>
#include <qlabel.h>
#include <qevent.h>
class Crosshair : public QLabel
{
Q_OBJECT
public:
Crosshair(QWidget *parent=0);
protected:
void mousePressEvent(QMouseEvent *);
private:
QTimer *timer;
private slots:
void timerfire();
};
#endif
crosshair.cpp:
Code:
#include <qapplication.h>
#include <qpushbutton.h>
#include <qtimer.h>
#include <qcursor.h>
#include <iostream>
#include "crosshair.h"
using namespace std;
int main(int argc,char **argv)
{
QApplication a(argc,argv);
Crosshair mousepos;
a.setMainWidget(&mousepos);
mousepos.show();
return a.exec();
}
Crosshair::Crosshair(QWidget *parent) : QLabel(parent)
{
setIndent(20);
resize(100,30);
move(1200,200);
setText("0,0");
timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(timerfire()));
timer->start(50,false);
}
void Crosshair::mousePressEvent(QMouseEvent *)
{
qApp->quit();
}
void Crosshair::timerfire()
{
QPoint p=QCursor::pos();
this->setText(QString().sprintf("%d,%d",p.x(),p.y()));
}
To build this, put both files in a directory called crosshair. cd to that directory and type
Code:
qmake -project
qmake
make
This does nothing more complex than inherit from a QLabel, set a timer to run 20x a second, grab the current cursor coordinates and write them into the label's text. Clicking in the window closes it. I use it for fixing up alignment bugs in JavaScript when I'm laying out objects.
You could open a file in the Crosshair class's constructor to store your data, and use gettimeofday(2) to get a timestamp. Nothing says Qt has to run in GUI mode (you can tell it explicitly not to in the QApplication constructor).
Qt from Trolltech: http://doc.trolltech.com

Related

Would that be possible to build a particular customized QPushButton?

I was trying to understand if there is a way to build a particular customized QPushButton?
What I am trying to achieve is the following layout and appearance:
The button is shown below, notice the red line (which meas that the button is not clicked). I am not sure how to achieve the red line. I think it could be widget? or a QProgressbar, that when is clicked goes/loads up to green..I am not sure because I don't have enough experience and have been trying to build it. However this seems to be a bit tough:
And below how it should look like right after the click happened (note the green line):
Despite my efforts, I found some useful sources that I could use to get me started: for example this source was great to understand how to start. I studied the fact that in order to achieve that, the button need to be subclassed, and that is great because it lays some sort of route.
Below the code I used:
custombutton.h
#ifndef CUSTOMBUTTON_H
#define CUSTOMBUTTON_H
#include <QPushButton>
class CustomButton : public QPushButton
{
public:
CustomButton( const QString& text, QWidget* parent = 0 );
void writeText();
};
#endif // CUSTOMBUTTON_H
custombutton.cpp
#include "CustomButton.h"
#include "algorithm"
CustomButton::CustomButton( const QString& text, QWidget* parent )
: QPushButton( text, parent )
{
}
void CustomButton::writeText()
{
QString buttonText = text();
setText( buttonText );
}
main
#include <QApplication>
#include "CustomButton.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CustomButton w( "MyButton" );
w.show();
w.writeText();
a.exec();
return 0;
}
Another useful source I found is this one which also was useful.
The official documentation points to use the styles, but I am trying not to do that because I would like to solve the problem understanding what is the potential of subclassing with Qt.
Unless going in the style direction is the only possible way to solve this problem?
I would like to thank anyone in advance for sharing or pointing to a potential solution on how to do that.
You can set your button as checkable and then set a different icon for the 2 states.
In your case you'd have to set the red icon for the Normal mode and the green one for the Selected mode
Here's an example:
https://www.dropbox.com/s/x40byuyu2ph8m1y/CheckableButton.zip?dl=0
Here someone asked the same thing:
https://forum.qt.io/topic/72363/change-icon-of-pushbutton
Here you can read abouth the modes:
https://doc.qt.io/qt-5/qicon.html#Mode-enum
PS: Of course overriding QAbstractButton::paintEvent(QPaintEvent *event) is a viable option too

Restore geometry and state of an arbitrary QDialog

In our applications we are using customizable dialogs using exhaustively QSplitter, so that our customers can rearrange the dialogs to fit their needs.
(Sometimes we are also using QDockWidget, but this seems to be similar.)
Now, it is very annoying to rearrange the dialog every time it is opened again. Or even between different starts of the program.
After consulting the documentation I was able to restore the state and the geometry of a specific dialog containing one QSplitter.
#include <QApplication>
#include <QLabel>
#include <QDebug>
#include <QSplitter>
#include <QPushButton>
#include <QTextEdit>
#include <QDialog>
#include <QSettings>
#include <QHBoxLayout>
int main(int argc, char** args) {
QApplication app(argc, args);
app.setOrganizationName("Tech");
app.setOrganizationDomain("qt.us");
app.setApplicationName("RestoreLayout");
app.setApplicationVersion("1.0");
QDialog dialog;
dialog.setLayout(new QHBoxLayout);
auto splitter = new QSplitter;
splitter->addWidget(new QLabel("Left"));
splitter->addWidget(new QLabel("Right"));
dialog.layout()->addWidget(splitter);
auto accept = new QPushButton("Accept");
accept->connect(accept, &QPushButton::clicked, [&](){
dialog.accept();
});
splitter->addWidget(accept);
auto geom= QSettings().value("Geom").toByteArray();
auto splitterState = QSettings().value("State").toByteArray();
qDebug() << geom;
qDebug() << splitterState;
dialog.restoreGeometry(geom);
splitter->restoreState(splitterState);
dialog.show();
dialog.connect(&dialog, &QDialog::accepted, [&]() {
QSettings().setValue("Geom", dialog.saveGeometry());
QSettings().setValue("State", splitter->saveState());
app.quit();
});
app.exec();
}
Unfortunately, this seems to be an approach, which is not usable in general.
Assume, that there is some arbitrary dialog, that needs to restore its geometry and state. Even worser QSplitter and QDockWidget might be even used in a nested fashion, which is done in our applications.
How can an outside programmer restore the geometry and the state of a arbitrary dialog that might be easily applicable to all possible dialogs?
For saving states of QDockWidget each it must be named: dockWidgetN->setObjectName("dock-widget-N");
But you can save only QMainWindow state for saving states of docks in this window.
You can separatelly save states via QSettings (it's QByteArray) and use some one state for many windows.
See here: How to save state of a dialog in Qt?

How can I get my caret to show up on first double-click action on a QGraphicsTextItem?

I am struggling to get a QGraphicsTextItem to work as a user friendly object.
Since it is very hard to move while being editable, I start it as not editable, and make it editable on double-click. Then turn editing off on losing focus.
My problem is, the caret does not show up on first edit.
I have tried getting the position based on mouse position (as in this question that was trying to solve a different problem), or calling the QGraphicsTextItem::mouseDoubleClickEvent(event);
No matter what I try, the caret is invisible on first action - until I start typing (or if I focus out and back in) - even though it is at the correct location.
After typing, or unselecting and reselecting , the caret shows up in normal location every time.
I have tried to call the QTextCursor in the item constructor, setting its position at 0, made no difference.
What made a difference : one of the 2 situations (neither of which I can do though):
a) start item with Qt::TextEditorInteraction in constructor
b) start item with no moving/focus/selectable flags
I can't do either - because my default state of item must be movable, and that interferes with text editing (as explained at start).
I have tried to disable those flags during editing though... with no effect.
Here is a simple code to demonstrate the problem, I hope somebody can have an idea.
mytextitem.h
#ifndef TEXTITEM_H
#define TEXTITEM_H
#include <QGraphicsTextItem>
class MyTextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
MyTextItem();
protected:
virtual void focusOutEvent (QFocusEvent * event);
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event);
};
#endif // TEXTITEM_H
mytextitem.cpp
#include "mytextitem.h"
#include <QTextCursor>
#include <QAbstractTextDocumentLayout>
#include <QGraphicsSceneMouseEvent>
#include <QFont>
MyTextItem::MyTextItem()
{
setHtml("ABCD");
setFont(QFont("Arial", 50));
setTextInteractionFlags(Qt::NoTextInteraction);
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
}
void MyTextItem::focusOutEvent(QFocusEvent *event)
{
Q_UNUSED(event);
setTextInteractionFlags(Qt::NoTextInteraction);
QTextCursor _cursor = textCursor();
_cursor.clearSelection();
setTextCursor(_cursor);
}
void MyTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
setTextInteractionFlags(Qt::TextEditorInteraction);
QGraphicsTextItem::mouseDoubleClickEvent(event); // or the version in linked question
}
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene s;
QGraphicsView view(&s);
s.setSceneRect(-20, -100, 800, 600);
view.show();
MyTextItem* t = new MyTextItem();
s.addItem(t);
return app.exec();
}
I have also considered editing text - not sure if that would work but I think it would affect the undo stack which I will have to deal with soon....
How can I get my caret to show up on first double-click action on the text item ?
(As a user, not seeing a caret would make me uncertain if I can type... even though it works... I would not have confidence in the object if I do not have feedback of my action. That's why I care about this problem.)
I can't explain it... after trying EVERYTHING to get the caret to show, the solution was so simple:
I had to change the order of flags being set, in constructor.
The QGraphicsTextItem flag must be set AFTER setting the QGraphicsItem flags.
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
setTextInteractionFlags(Qt::NoTextInteraction);

QTextBrowser - how to identify image from mouse click position

I'm using a QTextBrowser to display rich text including a number of images, each of them specified with a HTML <img> tag and added as resources using QTextDocument::addResource().
What I'd like to be able to do is, in a context menu handler (i.e. with a mouse click position available), identify the image that the click was over. It's possible to tell whether the click is over an image, because cursorForPosition(event->pos()).block().text() returns a string starting with Unicode 0xFFFC. Unfortunately the same string is returned for every image in the view.
It's possible to get all of the formats in use with QTextDocument::allFormats(), identify which of those are image formats, and get their image resource name. Unfortunately there seems to be no way to get their actual display position or bounding rectangle.
From the documentation:
Inline images are represented by an object replacement character (0xFFFC in Unicode) which has an associated QTextImageFormat. The image format specifies a name with setName() that is used to locate the image.
You can use charFormat().toImageFormat().name() on the cursor to extract the image's URL. Below is a self-contained example. There are two noteworthy details:
The cursor will sometimes point one character prior to the image. Thus the workaround; it seems necessary for both Qt 4.8.5 and 5.1.1.
The pop-up menus should be shown asynchronously so as not to block the rest of the application. The example code provided in the documentation is a source of bad user experience and should be considered an evil abomination. All widgets can automatically delete themselves when they get closed, so the menus won't leak. A QPointer is used only to demonstrate this fact. It tracks the menu's lifetime and nulls itself when the menu deletes itself.
#include <QApplication>
#include <QTextBrowser>
#include <QImage>
#include <QPainter>
#include <QMenu>
#include <QContextMenuEvent>
#include <QTextBlock>
#include <QPointer>
#include <QDebug>
class Browser : public QTextBrowser
{
QPointer<QMenu> m_menu;
protected:
void contextMenuEvent(QContextMenuEvent *ev) {
Q_ASSERT(m_menu.isNull()); // make sure the menus aren't leaking
m_menu = createStandardContextMenu();
QTextCursor cur = cursorForPosition(ev->pos());
QTextCharFormat fmt = cur.charFormat();
qDebug() << "position in block" << cur.positionInBlock()
<< "object type" << cur.charFormat().objectType();
if (fmt.objectType() == QTextFormat::NoObject) {
// workaround, sometimes the cursor will point one object to the left of the image
cur.movePosition(QTextCursor::NextCharacter);
fmt = cur.charFormat();
}
if (fmt.isImageFormat()) {
QTextImageFormat ifmt = fmt.toImageFormat();
m_menu->addAction(QString("Image URL: %1").arg(ifmt.name()));
}
m_menu->move(ev->globalPos());
m_menu->setAttribute(Qt::WA_DeleteOnClose); // the menu won't leak
m_menu->show(); // show the menu asynchronously so as not to block the application
}
};
void addImage(QTextDocument * doc, const QString & url) {
QImage img(100, 100, QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::white);
QPainter p(&img);
p.drawRect(0, 0, 99, 99);
p.drawText(img.rect(), url);
doc->addResource(QTextDocument::ImageResource, QUrl(url), img);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextDocument doc;
Browser browser;
doc.setHtml("<img src=\"data://image1\"/><br/><img src=\"data://image2\"/>");
addImage(&doc, "data://image1");
addImage(&doc, "data://image2");
browser.show();
browser.setDocument(&doc);
return a.exec();
}

qt: How to animate the transparency of a child QPushButton using QPropertyAnimation?

I want to progressively decrease the opacity of a QPushButton over a time of 2 seconds to complete transparency. For that I used the QPropertyAnimation class and used the property "windowOpacity" of the button to achieve the effect. But that worked only for a standalone QPushButton. When I assigned a parent to the button, the effect disappeared. Is there any way of achieving the same effect for child buttons ?
The windowOpacity property only applies to top level windows so it won't help you with animating transparency on child widgets unfortunately.
Standard controls are a bit problematic as well as there are many considerations contributing to their final appearance. There are many approaches you could take but they will all involve a certain amount of coding. There is no easy way :)
To set the transparency of a QPushButton, you would need to either set a stylesheet for it, or change some of the properties of the palette. Since neither of these options are directly usable by a QPropertyAnimation, you can create your own custom property and animate that.
Below is some code that specifies a custom property for a MainWindow called alpha. The alpha value is used to set the alpha portion of the button color. With this property in place, we can use QPropertyAnimation to animate it. The result is a button that fades in and out. This only handles the buttons background and not the text but it should provide a starting point for you.
MainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QPushButton>
class MainWindow : public QWidget
{
Q_OBJECT
Q_PROPERTY(int alpha READ alpha WRITE setAlpha);
public:
MainWindow();
virtual ~MainWindow();
private:
int m_alpha;
QPushButton * m_button1, *m_button2;
int alpha() const;
void setAlpha(const int a_alpha);
};
#endif /* MAINWINDOW_H */
MainWindow.cpp: (Updated to include stylesheet transparency example)
#include <QPlastiqueStyle>
#include <QPropertyAnimation>
#include "MainWindow.h"
MainWindow::MainWindow() :
m_button1(0),
m_button2(0),
m_alpha(255)
{
resize(200, 200);
QPalette windowPalette(palette());
windowPalette.setBrush(QPalette::Background, QBrush(QColor(200, 0, 0)));
setPalette(windowPalette);
m_button1 = new QPushButton(this);
m_button1->setText("Palette Transparency");
m_button1->setAutoFillBackground(false);
// NOTE: Changing the button background color does not work with XP Styles
// so we need to use a style that allows it.
m_button1->setStyle(new QPlastiqueStyle());
m_button2 = new QPushButton(this);
m_button2->move(0, 50);
m_button2->setText("Stylesheet Transparency");
m_button2->setAutoFillBackground(false);
m_button2->setStyle(new QPlastiqueStyle());
QPropertyAnimation *animation = new QPropertyAnimation(this, "alpha");
animation->setDuration(1000);
animation->setKeyValueAt(0, 255);
animation->setKeyValueAt(0.5, 100);
animation->setKeyValueAt(1, 255);
animation->setLoopCount(-1);
animation->start();
}
MainWindow::~MainWindow()
{
}
int MainWindow::alpha() const
{
return m_alpha;
}
void MainWindow::setAlpha(const int a_alpha)
{
m_alpha = a_alpha;
QPalette buttonPalette(m_button1->palette());
QColor buttonColor(buttonPalette.button().color());
buttonColor.setAlpha(m_alpha);
buttonPalette.setBrush(QPalette::Button, QBrush(buttonColor));
m_button1->setPalette(buttonPalette);
QString stylesheet("background-color: rgba(0,200,0," + QString::number(m_alpha) + ");");
m_button2->setStyleSheet(stylesheet);
}
main.cpp:
#include <QtGui/QApplication>
#include "MainWindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow m;
m.show();
return app.exec();
}
I faced the same problem a while ago and came to basically the same solution(manipulating the controls palette). But, while the helper property in the MainWindow is surely a quick and easy solution, it's a dirty one too. So, at least for larger and reoccurring usage it seamed much more appropriate to create a new animation class covering those needs. This isn't much more code(simply inherit QAbstractAnimation, move that palette stuff in there and pass the target control as a parameter into that class) but it keeps your parent control(like the mainwindow-class) free from such animation implementation details which surely don't belong in there.

Resources