QFileDialog used as widget - qt

My goal is: user can choose file (only *mp3) and after clicking twice on it it should play (so the QString to file should be send to play() function)
Firstly I started to work with QTreeView, but it has signal when the file is selected.
So I decided to create QFileDialog and used it as widget built-in into MainWindow.
The only problem that I have, that after double-click it disappears. It is possible to avoid it?
Should I work with some QDialog::finished() signal or, QDialog::done()?

First, you can get a double-click signal from QTreeView; it's:
void doubleClicked( const QModelIndex & index );
Second, if you really want to use the QFileDialog that way, first override closeEvent( QCloseEvent * event). Inside, if you want to close the dialog, do event->accept();, otherwise just do event->ignore();. Connect to QFileDialog::currentChanged( const QString & path ); to get the filename the user double-clicks. One last thing--be sure to create the QFileDialog on the heap (using new), not on the stack (a local), and call show() on it instead of exec().
Remember that you can supply it with a parent (this) and you won't need to delete it later.

connect(file_dialog, SIGNAL(finished(int)), file_dialog, SLOT(open()));
This seems to work fine. The geometry stays fixed and it remembers the last path allright..

Related

QT: How to close multiple windows of the same widget?

I'm a beginner in programming in C++/Qt.
I created a widget called wexample in Qt. When displayed, there is an button event that will open another window of the same widget wexample, and so on. My question is how to close all the windows of that widget?
I open my first widget as follows:
wexample *w = new wexample;
w-> show();
Inside the widget, I also have these events:
void wexample::on_pushButton1_clicked()
{
wexample *w = new wexample;
w -> show();
}
void wexample::on_pushButton2_clicked()
{
QWidget::close();
}
So when button 1 is pressed, it will open a new window and so on. When button 2 is pressed, it will close the window where the button is. Is there a way to close all of the windows from that widget all at once? Or even better, is there a way to close specific windows (for example, all the windows after the 3rd one)?
I have tried using signal and slot but I can't connect them since they are all of the same name. I would have to declare all of the widgets beforehand for it to work but I cannot know how many of them the user will need.
I'm sorry if my question isn't clear. I am really a beginner and have been searching for a while but couldn't find an answer. Maybe the structure as a whole doesn't make sense. Please help. Thanks.
You should add your newly created wexample's to a list and then iterate through them when you'd like to close them:
class wexample : public QDialog
{
...
private Q_SLOTS:
void on_pushButton1_clicked() {
wexample *w = new wexample(this);
m_wexamples.append(w);
w->show();
}
void wexample::on_pushButton2_clicked() {
foreach (wexample *w, m_wexamples)
w->close();
}
private:
QList<wexample*> m_wexamples;
};
A few extra points here:
Notice that I added (this) to the wexample constructor above. This ensures that the dialog is properly parented (and therefore will be cleaned up if you don't manually delete the object yourself). Previously, you would have been leaking memory every time you showed the dialog
The slot for the second button simply iterates through the list of dialogs and closes them. This does NOT mean that the dialogs have been deleted (and in fact are still in the list after closing them). If you'd prefer to fully remove them, then use of the "take" methods of QList, removing the dialog from the list and then call dialog->close(); dialog->deleteLater(); on it
This is a somewhat contrived example, you probably won't be opening the dialog from within the dialog's implementation in practice

Reliably showing a "please wait" dialog while doing a lengthy blocking operation in the main Qt event loop

I've got a Qt app that needs to call an expensive non-Qt function (e.g. to unzip a ~200MB zip file), and since I'm calling that function from the main/GUI thread, the Qt GUI freezes up until the operation completes (i.e. sometimes for 5-10 seconds).
I know that one way to avoid that problem would be to call the expensive function from a separate thread, but since there isn't much the user can do until the unzip completes anyway, that seems like overkill. I can't add processEvents() calls into the expensive function itself, since that function is part of a non-Qt-aware codebase and I don't want to add a Qt dependency to it.
The only thing I want to change, then, is to have a little "Please wait" type message appear during the time that the GUI is blocked, so that the user doesn't think that his mouse click was ignored.
I currently do that like this:
BusySplashWidget * splash = new BusySplashWidget("Please wait…", this);
splash->show();
qApp->processEvents(); // make sure that the splash is actually visible at this point?
ReadGiantZipFile(); // this can take a long time to return
delete splash;
This works 95% of the time, but occasionally the splash widget doesn't appear, or it appears only as a grey rectangle and the "Please wait" text is not visible.
My question is, is there some other call besides qApp->processEvents() that I should also do to guarantee that the splash widget becomes fully visible before the lengthy operation commences? (I suppose I could call qApp->processEvents() over and over again for 100mS, or something, to convince Qt that I'm really serious about this, but I'd like to avoid voodoo-based programming if possible ;))
In case it matters, here is how I implemented my BusySplashWidget constructor:
BusySplashWidget :: BusySplashWidget(const QString & t, QWidget * parent) : QSplashScreen(parent)
{
const int margin = 5;
QFontMetrics fm = fontMetrics();
QRect r(0,0,margin+fm.width(t)+margin, margin+fm.ascent()+fm.descent()+1+margin);
QPixmap pm(r.width(), r.height());
pm.fill(white);
// these braces ensure that ~QPainter() executes before setPixmap()
{
QPainter p(&pm);
p.setPen(black);
p.drawText(r, Qt::AlignCenter, t);
p.drawRect(QRect(0,0,r.width()-1,r.height()-1));
}
setPixmap(pm);
}
Moving to another thread is the correct way to go but for simple operations, there's a much less complicated way to accomplish this without the pain of managing threads.
BusySplashWidget splash("Please wait…", this);
QFutureWatcher<void> watcher;
connect(&watcher, SIGNAL(finished()), &splash, SLOT(quit()));
QFuture<void> future = QtConcurrent::run(ReadGiantZipFile);
watcher.setFuture(future);
splash.exec(); // use exec() instead of show() to open the dialog modally
See the documentation about the QtConcurrent framework for more information.

In QTableView, What "signal" triggers the editing mode

I'm trying to write some Inherit class (Let's call it A) from QTableView, and hope to overwrite the slot
void edit ( const QModelIndex & index )
from QAbstractItemView. I know that this function can trigger editing mode, but here is my question: I hope that whenever editing mode are triggered by user in this class A, the program can go inside the overwritten slot A::edit.
However, it seems only when A::edit are directly called, the program can get in.
Since QTableView comes from QAbstractItemView, if the editing mode is triggered by other way(such as mouse double click), the program will run default QAbstractItemView::edit instead of A::edit.
I tried to connect the signal "activated", but apparently it's not the correct signal to trigger editing mode. Is there anyway to do something every time when an editor is triggered?
Also, I'd like to do something when the editing mode is ended by pressing Enter or ESC or mouse clicking on other place. The same situation happens at the slot
void editorDestroyed ( QObject * editor )
Can anyone help me to solve this problem?
I'll really appreciate it, thanks!
QAbstractItemView::edit(const QModelIndex& index) is not virtual, so that's why when you call it directly you get your subclass's behavior, but when existing code calls it they get they base class behavior. If that doesn't ring a bell, read that link; Qt has a lot of virtual and non-virtual functions and knowing what the difference is will save you a lot of headaches.
However, QAbstractItemView::edit(const QModelIndex& index, EditTrigger trigger, QEvent* event) is virtual, so you can override it. I haven't verified it, but presumably the non-virtual edit() calls this edit(), so it should have the same effect.
QAbstractItemView::editorDestroyed(QObject* editor) is also virtual, so I'm not sure why it isn't be working. However, there is also QAbstractItemView::closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint) which is also virtual, so you might want to try reimplementing that in your subclass. The closeEditor() documentation also suggests commitData(), which is also virtual. The Qt item views have a lot of similar methods, so don't assume that the first one you see is going to do exactly what you want/expect.
FYI, in case your not used to reimplementing virtual methods in a subclass, the fastest/easiest way to make sure your implementation is being called is to do something like:
class A : public QTableView {
void closeEditor ( QWidget * editor, QAbstractItemDelegate::EndEditHint hint ) {
qDebug("my closeEditor was called!");
// call the real implementation so that the base class continues to work properly
QTableView::closeEditor(editor, hint);
}
};
You could do this with edit(), editorDestroyed(), closeEditor(), and commitData() to see which ones are called when.

How can I programmatically commit data from QTableWidget, which contain some items in editing state?

How can I autocommit data from QTableWidget, that is in editing state, when I fire some command?
Assume, that there is some grid and data in it (editable thorough delegate that fires QComboBox editor). So, one starting to select option in combo, but do not finish editing, then hit some button, that executes action, that uses data from that combo, but new choise is not committed yet :\
How can I programmatically finish editing in table?
I mean some not strict 'loop all items and finish editing' way, that I consider as bad and ugly.
OOPS: worked too much, so, haven't realised, that there could be only one pending editor at time. Question is still here.
There is a protected slot named "commitData" in the tableWidget. You can inherit from tableWidget, then add your own public method (or slot) and send a signal (or simply call commitData method) from there.
There is one problem. You'll need to provide the editor object, but tableWidget gives you no way to get the pointer you need.
If you're using your own createEditor method, you can save the pointer to the editor somewhere, where your method can get it. It's a hack, but it's the only way i know.
The current editor does not seem to be accessible from outside of the view, but its content is committed when the current model index changes. So a simple way to force a commit seems to be to call
table->setCurrentIndex (QModelIndex ())
plus restoring your previous current index afterwards if the widget is not discarded yet.
This is quite an old question but it still came up quite high on Google so just in case anyone else needs the answer QTableView has a protected method
void currentChanged(const QModelIndex &current, const QModelIndex &previous)
which causes the data to be commited and QTableWidget is built on QTableView so that should still work. I found this info on the Qt Forum.

QPlainTextEdit segmentation fault

I have some Qt application with QPlainTextEdit in Tab widget. When try to make a pointer on it
QPlainTextEdit *w = (QPlainTextEdit*)ui->tabWidget->widget(0)
and call a document() method
w->document()
I get a segfault.
But if i call document directly, e.g. ui->mainEdit->document(), then everything works fine.
Can anybody explain me why it happens?
You want to do:
QPlainTextEdit *w = ui->mainEdit;
Then w->document() will return what you want. You are getting the segmentation fault because when you cast ui->tabWidget->widget(0); gives a pointer to a tab page object. When you cast this to QPlainTextEdit* are telling your program to treat a part of memory that does not represent a QPlainTextEdit as a QPlainTextEdit. This causes trouble at the time that you call w->document() because that is in the memory location that it tries to access is not what it would expect from memory which belongs to QPlainTextEdit.
i'm almost sure, that ui->tabWidget->widget(0) return container widget inside of tabWidget. Try qDebug() << ui->tabWidget->widget(0)->metaObject()->className() and see what is printed. It's probably just "QWidget" not "QPlainTextEdit". Your edit is inside of layout of this widget
You can use qobject_cast to make sure that it returns the right type.
QPlainTextEdit *w = qobject_cast<QPlainTextEdit*>(ui->tabWidget->widget(0));
if (w)
{
...
}
It'll return 0 if the type is not of QPlainTextEdit*.
As stated, widget(0) is probably not returning what you wanted - and probably contains a container or some other item, and is probably not the way you want to be accessing your widgets unless there is no other way.

Resources