Paste event in Qt - qt

I want to build a structured document editor using Qt. The base concept for v1 is nested sections, each section having a title and one or more paragraphs. Sections and paragraphs are distinct visual units (probably via background shading). I also need to be able to store character-level semantics (ie: this run of text is associated with reference X). If I wanted to build a read-only view of this it would be doable with QFrame for the sections and a QLabel for each title and each paragraph. To make this editable I'm pretty sure I can capture all keyboard events to the window and implement a cursored text-entry-and-editing feel that way.
What I'm having trouble with is how to handle copy/paste.
I want the clipboard interactions to feel native: that is, ctrl+c/v on window, command+c/v on OSX, ctrl+c/v for clipboard on X, select to copy for PRIMARY on X, middle click to paste for PRIMARY on X, etc.
The standard text editing controls in Qt handle all of this just fine. I'm wondering if there is some sort of "paste event" or similar that I can grab to implement the same thing in my custom widget? Is there another way?

For native keyboard shortcuts, you can add them to menu items:
ui->actionCut->setShortcut(QKeySequence::Cut);
ui->actionCopy->setShortcut(QKeySequence::Copy);
ui->actionInsert_empty_row->setShortcut(Qt::Key_Insert);
ui->actionPaste->setShortcut(QKeySequence::Paste);
ui->actionRemove->setShortcut(QKeySequence::Delete);
See QKeySequence docs

There's no paste signal/event as far as i know to listen to, though there's nothing stopping you from taking a sneak look at how the paste() slot is implemented in widgets like QLineEdit and implement your own if possible. The afferent signal is not that important, since it's just a signal and you can trigger that whenever you desire(eg. Ctrl+v, context menu or program menu).
LE: If i think better, you might be thinking this the wrong way, you don't need a signal, you just need the slot that you can call whenever the action is called by any means you wish(eg. ctrl+v). Once you have the slot(QClipboard), it's just a matter of properly connecting it to the desired triggering actions/signals.

I'm not completely sure why you would want to do it with a QLabel and then capture the keys when there are already classes that handle text edition for you (and you can even override the key pressed funcionality)
If you want to have editable text, you could use a QTextEdit or a QPlainTextEdit and those classes already handle the copy-paste functionality (even with right click menu and everything).
If you want to add special a special behavior to your copy and paste, you can override the Mime functions:
//in your header file, add
void insertFromMimeData(const QMimeData *source) override; // override for paste
QMimeData * createMimeDataFromSelection() const override; // override for copy
// in the cpp:
//it would be something like this:
void YourTextField::insertFromMimeData(const QMimeData *source) {
// Do something special on the paste event, maybe even create your own "source"
//call the base class insert
QPlainTextEdit::insertFromMimeData(source);
}
Note: I'm not 100% with the copy, since I only overrode paste, but I'm almost certain that that's the right function.

Related

How to intercept / modify excape key functionality in Qt

I am trying to fix a bug in a Qt app which I did not write. The window changes the background color of the entire window to red and puts up some buttons, dialog boxes, etc. When the escape key is pushed, the boxes and buttons go away, leaving an empty red screen. The Cancel button does the right thing in returning to the previous window. I think I need to somehow be notified of when the escape key is pushed, and then call the same function as the cancel pushbutton does. Hopefully, I can limit the scope of this special action to when the problem window is up. I am an experienced programmer but a complete Qt newbie. This app is purely C++. To my knowledge, it does not appear to use any QML. I am still searching through the Qt online documentation, but any suggestions / examples are appreciated.
This depends a lot on your specific Qt version and setup of your application. That said, I'll take a shot at helping. In the class where you're trying to intercept the escape key press, assuming it's inheriting QObject, simply override the virtual function eventFilter. Inside your overridden instance of eventFilter, check that the QEvent type is a QEvent::KeyPress, and then check whether the key of that KeyPress is the escape key, and handle as needed.
Be sure that you pass the event out of your function, else you'll see your overridden function eat all events. If you explicitly want the event to be "eaten", simply do not return it from your function. For specifics and examples, check out documentation of QObject::eventFilter().

How to enable both internal reordering and external dropping in a Qt widget?

I have created a widget which inherits QListWidget.
My goal is for it to accept files dropped into it from an external file manager, and for the user to be able to reorder the elements in the widget. I can achieve both, but not at the same time.
If I just set
myWidget->setDragDropMode(QListView::InternalMove);
myWidget->setDragEnabled(true);
I can reorder the items within the widget, but I can't drop external items into it.
If I reimplement the dragMoveEvent, dragEnterEvent and dropEvent events, all of them just having acceptProposedAction(); and some debug messages inside them, I can drop external files into my widget, but I can no longer rearrange the items.
Is there a way to have the above two at the same time, or do I have to manage the items myself in the reimplemented functions? If so, how can I know if a dropped item is internal or external, and how can I know from which position it was taken and into which position in the list it was dropped into?
If I parse the mimeData which I got from the event, I can see whether it as a file or a text, and I get "qabstractitemmodeldatalist" if it was an internal item, but it still doesn't give me its position.
I can check event->pos() to know in pixels where the drop has been made, and event->source() to learn about what was dropped there, but is this really best practice, to start calculating pixel values and adding objects "manually"?
The solution was very simple: I just had to call the functions of the parent class at the end of each function I've overridden.
void myWidget::dropEvent(QDropEvent *event)
{
do_stuff_with_received_data(event);
QListWidget::dropEvent(event);
}

Qt Editable QGraphicsTextItem validating text and emitting signal on change

I am really stuck up with a task relating to Qt GraphicsView. Any help or suggestions will be highly appreciated.
In my QGraphicsView application, I have a few editable QGraphicsTextItems that I have added to the scene. I need the following functionality:
Setting validator for float so that the user does not by mistake enter a character or new line in that text item.
Emitting a signal once the text is changed by the user.
Can anyone please suggest how I can implement this in my application? I have tried real hard but I am not able to find anything suitable. If there is any alternative or workaround, I'll be grateful to know.
Thanks!
QGraphicsTextItem does not support this ability, as I'm sure you have discovered. So you have a few options:
Reimplement focusOutEvent(QFocusEvent* event) and/or keyReleaseEvent(QKeyEvent* event) to detect when you validator needs to run. A QValidator can be created as a member of your text class, and queried either when focus is lost and/or a key is pressed (the enter key to signify completion, or on every letter). Then just create a custom signal for you when deem the editing to have finished or changed.
Use a GraphicsProxyWidget to hold a 'real' QLineEdit for text entry, just set it up with a validator as you would if placing in a traditional GUI form. You will need to 'forward' the editingFinished() or textEdited(const QString& text) signal from the QLineEdit to your QGraphicsTextItem, so you don't have to provide external access to the widget.
You could also use the internal QTextDocument of the QGraphicsTextItem, this is what actually holds and formats the text (access it with document()). However it doesn't support having a QValidator installed, so you would have to create a signal-slot loop whereby when the text is changed (signalled by contentsChanged()) it's received by the QGraphicsTextItem, validated, then either updated/cleared if it fails validation (which will update the QTextDocument, and trigger this process again) or ignored if it passes.
Neither is difficult to implement; the first requires more code but will give you more control over the visual appearance of the text box.

How can I customize the appearance of the actions in my QToolBar?

I have just changed some toolbars from Q3ToolBars (with QToolButtons explicitly added to them) into Q4 toolbars (with actions added to them straight away instead.)
The old tool buttons had a nice outline around them, but this is not displayed in the new version; the QActions in the Q4 toolbar just look like a line of icons. Is there a way to change the 'button' style in the new version (assuming these actions can be considered as such) and give them the outline? I've looked through the QToolBar reference, but the toolButtonStyle() function only appears to work with whether you want to display icon, text, etc.
...Or will I have to just make actual tool buttons and/or QPushButtons and use addWidget()?
The widget associated with a given action is accessible through QToolBar::widgetForAction (since Qt 4.2). So, you can pass your actions to this method, get the QWidgets returned by it, convert them to QToolBar, and handle them like you normally would (code not tested):
// ...
auto toolButton =
static_cast<QToolButton *>(
m_ui.toolbar->widgetForAction(m_ui.my_Action));
// Will make the toolButton always appear raised:
toolButton->setAutoRaise(false);
// ...
As far as I've been testing, some methods might not work (i.e., QWidget::hide), so do your own testing.
Yes, of course you can edit look of QToolButtons in two different ways:
You can set it style sheet using void QWidget::setStyleSheet(const QString &)
You can reimplement QToolButtons class with new paintEvent function where you will be able to exactly set how your button should looks like.

how can I have more than a UI for a QMainWindow?

I would like to have a QMainWindow that can change it's look at runtime, i.e when a user clicks a button. Besides keeping references to different UI classes generated by the QtDesigner, is there another way of doing that? Maybe by storing each UI in a layout ? What do you think ?
How much of the main window do you want to change? You could use a QStackWidget any place you want to change things, and change the shown page of the widget when the button is pressed. This will be quick to change, but for large or complicated UIs it may be slightly slower at startup, since it will be creating the widgets for both UIs at the same time. (There are fairly easy ways to change this, also, but they do add complications to something that could be straightforward for most people.) Also, if both layouts should have the same data, just in different places, you have the additional overhead of keeping both sets of UIs up to date while the program is running.
I think I got it now.
You have a QMainWindow and when a certain event is triggered you want to change the appearance of that particular window, like remove some buttons, add a treeview widget or what not.
Well the straight forward approach would be to do it manually, remove some widgets and add new ones using regular C++ code. This can be abit hard if you're used to Qt Designer.
The other way I can think of is using Qt Designer to generate the code for the other appearances and copy it to a special function. The code generated by Qt Designer is usually in a header file called "ui_classname.h" and isn't hard to understand. You will however need to remove some of it as not all would be necessary.
Also, instead of copying the generated code from Qt Designer you could just call it. Usually your widget has a pointer to the generated class and in your widget's constructor you see something like this:
MyWindow::MyWindow(QWidget *parent) : QMainWindow(parent), m_ui(new Ui::MyWindow)
{
m_ui->setupUi(this);
}
and in the corresponding header file:
class MyWindow : public QMainWindow {
...
private:
Ui::MyWindow *m_ui;
};
You could add the additional generated classes for the other appearances and use them when your event triggers.
It might look like this:
class MyWindow : public QMainWindow {
...
private:
void changeAppearance(int id);
Ui::MyWindow *m_ui;
Ui::MyWindowFirstAppearance *m_uiFirst;
Ui::MyWindowSecondAppearance *m_uiSecond;
...
};
void MyWindow::changeAppearance(int id)
{
// some code to remove the current appearance, basically the opposite of what setupUi is doing
if (id == 0)
m_ui->setupUi(this);
else...
m_uiFirst->setupUi(this);
...
}
This has the benefit of using the generated classes directly, so every change you do in Qt Designer doesn't require a change to your main window. The problem is I'm not sure if it's legal to call setupUi more than once and in a place other than your widget's constructor, so you'll have to check that (by looking at what's happening in the setupUi function).
You can dynamically load UI layouts at runtime. Check Qt documentation for QUiLoader class.
This also enables you to upgrade UI layouts without modifying a single line of code.
What I do is to design two UIs under two different QFrames, put the two QFrames in a layout together in the QMainWindow, and then hide() and show() the correct QFrame that you want...
You can use a QTabWidget and hide its buttons. You can then design each GUI in a separate window of the tabWidget. It has the advantage over hiding frames that you won't clutter up your Qt Creator window.
If I'm getting this right, I think you might want to take a loot at style sheets. It allows you to have "skins" for your widgets, much like CSS.
If I didn't get this right, and what you're trying to do is generate .ui files on the fly and create widgets with those using QUiLoader, then you're probably going at this the wrong way since I can't think of a good reason a regular application would need that.

Resources