Why doesn't drag and drop pictures work on this QTextEdit? I have tried everything.
here is the class TextEdit:
//textedit
class TextEdit : public QTextEdit
{
Q_OBJECT
public:
TextEdit(QWidget*parent) : QTextEdit(parent)
{
this->setAcceptDrops(true);
}
virtual void dragEnterEvent(QDragEnterEvent *e)
{
e->accept();
//QTextEdit::dragEnterEvent(e);
}
virtual void dragLeaveEvent(QDragLeaveEvent *e)
{
e->accept();
//QTextEdit::dragLeaveEvent(e);
}
//
virtual void dragMoveEvent(QDragMoveEvent *e)
{
e->accept();
// QTextEdit::dragMoveEvent(e);
}
virtual void dropEvent(QDropEvent *e)
{
QTextEdit::dropEvent(e);
}
bool canInsertFromMimeData(const QMimeData *source ) const
{
if (source->hasImage())
return true;
else
return QTextEdit::canInsertFromMimeData(source);
}
void insertFromMimeData( const QMimeData *source )
{
if (source->hasImage())
{
QImage image = qvariant_cast<QImage>(source->imageData());
QTextCursor cursor = this->textCursor();
QTextDocument *document = this->document();
document->addResource(QTextDocument::ImageResource, QUrl("image"), image);
cursor.insertImage("image");
}
}
};
context context context context context context context context context context context context context context context context context context context context context context context context context context context context context context context context
It depends on what application you are dragging the images from and what data that application decides to include in the operation. If it is not working for you, it is because whatever you are dropping contains no image data and probably only contains a URL or file path.
Dragging images from the file explorer under Windows 7 for me at least does not work but opening an image in the latest version of Firefox and dragging that onto the text edit does work. Try it :)
Related
I have a dialog with two buttons in the title bar: the context help button and the close button. How can I find out that the user clicked the context help button to perform my custom action? (I want to show some help page in the browser as in VS dialogs.)
I found a similar question, but how to do this with qt?
Context help button behaviour on CPropertySheet
Update.
Now I use the code like this:
class MyHelper : public QObject
{
Q_OBJECT
public:
explicit MyHelper( QObject * parent = nullptr ) {
qApp->installEventFilter( this );
}
protected:
virtual bool eventFilter( QObject * obj, QEvent * ev ) override {
if ( ev->type() == QEvent::EnterWhatsThisMode ) {
showHelp( QApplication::activeWindow() );
return true;
}
return QObject::eventFilter( obj, ev );
}
private:
void showHelp( QWidget * sender ) {
//TODO
}
};
I believe that QWidget::nativeEvent is what you are looking for.
Is there any way to check that the ui elements(line edit,combo box,etc.) of the dialog has been changed.
What I want is to show a message to the user if he changes the value of any single ui element, saying that details have been partially filled.
What i can do is use connect for each ui element & based on the value changed of each element i am setting a boolean flag & at the time of close event i am checking that boolean flag.
But Its quite complicate to check it for each widget.
Is there any easier way.
Code that I am using for single ui element is,
connect(ui->leAge,SIGNAL(textChanged(QString)),this,SLOT(functChanged())); //In Constructor
void DemoDialog::functChanged() //Will be called if value of line edit (ui->leAge) is changed
{
flag=true;
}
void DemoDialog::closeEvent(QCloseEvent *event)
{
if (flag) {
if (QMessageBox::warning(this,"Close","Do you want to close?",QMessageBox::Yes|QMessageBox::No)==QMessageBox::Yes) {
this->close();
}
}
You can't reimplement closeEvent to prevent closing a window. The close() call that you do is either redundant or an error (infinite recursion), since a closeEvent method call is just a way of being notified that a closing is imminent. At that point it's too late to do anything about it.
Keep in mind the following:
Closing a dialog usually is equivalent to canceling the dialog. Only clicking OK should accept the changes.
When a user wants to close a dialog, you don't have to ask them about it. They initiated the action. But:
It is proper to ask a user about dialog closure if there are changes have not been accepted - on platforms other than OS X.
So, you have to do several things:
Reimplement the void event(QEvent*) method. This allows you to reject the close event.
Offer Apply/Reset/Cancel buttons.
Your flag approach can be automated. You can find all the controls of the dialog box and set the connections automatically. Repeat the statement below for every type of control - this gets tedious rather quickly:
foreach(QTextEdit* w, findChildren<QTextEdit*>())
connect(w, SIGNAL(textChanged(QString)), SLOT(functChanged()));
You can leverage the meta property system. Most controls have a user property - that's the property that holds the primary value of the control (like text, selected item, etc). You can scan all of the widget children, and connect the property change notification signal of the user property to your flag:
QMetaMethod slot = metaObject().method(
metaObject().indexOfSlot("functChanged()"));
foreach (QWidget* w, findChildren<QWidget*>()) {
QMetaObject mo = w->metaObject();
if (!mo.userProperty().isValid() || !mo.userProperty().hasNotifySignal())
continue;
connect(w, mo.notifySignal(), this, slot);
}
Each widget is a QObject. QObjects can have properties, and one of the properties can be declared to be the user property. Most editable widget controls have such a property, and it denotes the user input (text, numerical value, selected index of the item, etc.). Usually such properties also have change notification signals. So all you do is get the QMetaMethod denoting the notification signal, and connect it to your function that sets the flag.
To determine the changed fields, you don't necessarily need a flag. In many dialog boxes, it makes sense to have a data structure that represent the data in the dialog. You can then have a get and set method that retrieves the data from the dialog, or sets it on the dialog. To check for changed data, simply compare the original data to current data:
struct UserData {
QString name;
int age;
UserData(const QString & name_, int age_) :
name(name_), age(age_) {}
UserData() {}
};
class DialogBase : public QDialog {
QDialogButtonBox m_box;
protected:
QDialogButtonBox & buttonBox() { return m_box; }
virtual void isAccepted() {}
virtual void isApplied() {}
virtual void isReset() {}
virtual void isRejected() {}
public:
DialogBase(QWidget * parent = 0) : QDialog(parent) {
m_box.addButton(QDialogButtonBox::Apply);
m_box.addButton(QDialogButtonBox::Reset);
m_box.addButton(QDialogButtonBox::Cancel);
m_box.addButton(QDialogButtonBox::Ok);
connect(&m_box, SIGNAL(accepted()), SLOT(accept()));
connect(&m_box, SIGNAL(rejected()), SLOT(reject()));
connect(this, &QDialog::accepted, []{ isAccepted(); });
connect(this, &QDialog::rejected, []{ isRejected(); });
connect(&buttonBox(), &QDialogButtonBox::clicked, [this](QAbstractButton* btn){
if (m_box.buttonRole(btn) == QDialogButtonBox::ApplyRole)
isApplied();
else if (m_box.buttonRole(btn) == QDialogButtonBox::ResetRole)
isReset();
});
}
}
class UserDialog : public DialogBase {
QFormLayout m_layout;
QLineEdit m_name;
QSpinBox m_age;
UserData m_initialData;
public:
UserDialog(QWidget * parent = 0) : QDialog(parent), m_layout(this) {
m_layout.addRow("Name", &m_name);
m_layout.addRow("Age", &m_age);
m_age.setRange(0, 200);
m_layout.addRow(&buttonBox());
}
/// Used by external objects to be notified that the settings
/// have changed and should be immediately put in effect.
/// This signal is emitted when the data was changed.
Q_SIGNAL void applied(UserData const &);
UserData get() const {
return UserData(
m_name.text(), m_age.value());
}
void set(const UserData & data) {
m_name.setText(data.name);
m_age.setValue(data.age);
}
void setInitial(const UserData & data) { m_initialData = data; }
bool isModified() const { return get() == m_initialData; }
protected:
void isAccepted() Q_DECL_OVERRIDE { emit applied(get()); }
void isApplied() Q_DECL_OVERRIDE { emit applied(get()); }
void isReset() Q_DECL_OVERRIDE { set(m_initialData); }
};
If you're only checking whether the input fields are filled when the Dialog closes, you don't need the flags you can only check if there is any input.
If you are filling the input fields programatically at some points but are also only interested in the change when the dialog closes, you can also check in the close function whether the current input is equal to the one you set earlier.
From the code you posted, I can't really see what you need the flags for.
I am new to QT. I have several QDialogs in my QT project. I have created a generic class to change the properties of widgets inside QDialogs. My generic class has a static method which will change the properties of widgets.
void MyClass::setFontsizeToWidgets(float modValue, QObject obj)
{
QFont f;
float pointSize = 0.0;
QList<QPushButton*> buttons = obj.findChildren<QPushButton*>();
foreach ( QPushButton * button, buttons)
{
f = button->font();
pointSize = f.pointSizeF();
f.setPointSizeF(pointSize*modValue);
button->setFont(f);
}
}
Now my questions is, how to pass the QDialog as a object to the above static method from QDialog class? So that the static method will change the font size of the QPushButton(s) in the QDialog.
You can do it like this:
void MyClass::setFontsizeToWidgets(float modValue, QObject *obj)
{
//do something
}
void MyDialog::someFunction() //this is a function of your QDialog class
{
MyClass::setFontsizeToWidgets(10, this);
}
How to make a QT dialog read-only? Any general way to implement it easily? For example
(1) set all its containing widgets disable. (how to implement it?)
(2) Intercept edit events like key pressed, mouse pressed but how not to intercept the one to close the dialog?
I think this feature should be very helpful.
Disabling the widgets can be done similar to the following:
void myDialog::disableWidgets()
{
QList<QWidget *> widgets = this->findChildren<QWidget *>();
foreach(QWidget* widget, widgets)
{
widget->setEnabled(false);
}
}
To intercept events, QDialog includes the function installEventFilter(QObject*).
This allows you to use a separate object to receive all events passed to the dialog. You can then choose to handle the event in the object, or pass it on to the dialog itself by calling the base class QObject::eventFilter
class MyEventHandler : public QObject
{
Q_OBJECT
protected:
bool MyEventHandler::eventFilter(QObject *obj, QEvent *event)
{
// handle key press events
if (event->type() == QEvent::KeyPress)
{
// Do something
// ...
return true; // event handled by the class
}
else
{ // ignore this event and pass it to the dialog as usual
return QObject::eventFilter(obj, event);
}
}
return false;
};
QDialog* dlg = new QDialog;
MyEventHandler evtHandler = new MyEventHandler;
dlg->installEventFilter(evtHandler);
Read-only is a strange term to apply to a dialog. Disabling all widgets as above does the trick. If you only wanted to make the input part of a QInputDialog read-only (while leaving scrollbars, buttons, etc. enabled), you could adapt that code as below:
QInputDialog dialog(this);
dialog.setOptions(QInputDialog::UsePlainTextEditForTextInput);
dialog.setWindowTitle("Title");
dialog.setLabelText("Label");
dialog.setTextValue("1\n2\n3\n");
QList<QWidget *> widgets = dialog.findChildren<QWidget *>();
foreach(QWidget* widget, widgets) {
if (strcmp(widget->metaObject()->className(),"QPlainTextEdit")==0) {
QPlainTextEdit *t = static_cast<QPlainTextEdit*>(widget);
t->setReadOnly(true);
}
}
dialog.exec();
Suppose there are checkboxes, options etc controls in a dialog box, how could I save the state of the dialog in Qt?
Should I use QSettings or something else?
Thanks.
I ran into the same problem.
Googling didn't help too much.
So in the end I wrote my own solution.
I've created a set of functions that read and write the state of each child control of a dialog at creation respectively destruction.
It is generic and can be used for any dialog.
It works like this:
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
QMoMSettings::readSettings(this);
}
Dialog::~Dialog()
{
QMoMSettings::writeSettings(this);
delete ui;
}
...
void QMoMSettings::readSettings(QWidget* window)
{
QSettings settings;
settings.beginGroup(window->objectName());
QVariant value = settings.value("pos");
if (!value.isNull())
{
window->move(settings.value("pos").toPoint());
window->resize(settings.value("size").toSize());
recurseRead(settings, window);
}
settings.endGroup();
}
void QMoMSettings::writeSettings(QWidget* window)
{
QSettings settings;
settings.beginGroup(window->objectName());
settings.setValue("pos", window->pos());
settings.setValue("size", window->size());
recurseWrite(settings, window);
settings.endGroup();
}
void QMoMSettings::recurseRead(QSettings& settings, QObject* object)
{
QCheckBox* checkbox = dynamic_cast<QCheckBox*>(object);
if (0 != checkbox)
{
checkbox->setChecked(settings.value(checkbox->objectName()).toBool());
}
QComboBox* combobox = dynamic_cast<QComboBox*>(object);
if (0 != combobox)
{
combobox->setCurrentIndex(settings.value(combobox->objectName()).toInt());
}
...
foreach(QObject* child, object->children())
{
recurseRead(settings, child);
}
}
void QMoMSettings::recurseWrite(QSettings& settings, QObject* object)
{
QCheckBox* checkbox = dynamic_cast<QCheckBox*>(object);
if (0 != checkbox)
{
settings.setValue(checkbox->objectName(), checkbox->isChecked());
}
QComboBox* combobox = dynamic_cast<QComboBox*>(object);
if (0 != combobox)
{
settings.setValue(combobox->objectName(), combobox->currentIndex());
}
...
foreach(QObject* child, object->children())
{
recurseWrite(settings, child);
}
}
Hope this helps someone after me.
QSettings will work fine for what you need, but you're essentially just serializing the options and reloading them at start up so there's plenty of documentation on doing it in Qt.