QMainWindow goes background after using QFileDialog - qt

I have a Qt application that loads some file after clicking on button. I am using QFileDialog to open files. Every time I close file dialog, the application main window (QMainWindow) is behind all other opened windows (internet browser, explorer etc.). Is this standard behaviour? And is there any way to prevent this? I tried
// set always on top window
Qt::WindowFlags flags = this->windowFlags();
this->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
but it causes that also file dialog is behind main window.
Edited:
Here is fragment of code to call file dialog (method that calls it is static method of my class LoadData):
void MainWindow::on_buttonIP_clicked()
{
loaded = LoadData::OpenFiles(IPFiles);
}
bool LoadData::openFiles(QStringList &fileNames)
{
// open files dialog
fileNames = QFileDialog::getOpenFileNames(0,
tr("Open files"), "", "Text Files (*.txt *.dat *.points)");
if (fileNames.isEmpty())
{
return false;
}
return true;
}

First argument of QFileDialog::getOpenFileNames must not be nullptr. Set it to your main window, and everything will be OK.

Related

VCL style affects non-VCL window

I have a problem with VCL styles in Embarcadero C++ Berlin 10.1.
I have an application written in BCB C++ and it calls pspiHost.dll (written in VS 2017), that executes Photoshop 8bf plugin filters (https://github.com/spetric/Photoshop-Plugin-Host).
Everything works OK until I change project application appearance to some VCL Style. When plugin is called from styled application, it's window is also styled!? Also, plugin window is constantly repainted and any action in window (like panning image) is slowed down.
I have also noticed this strange behavior on one scanner preview dialog which was also styled and it was definitely not a VCL application.
How can I disable VCL styling for non-VCL windows called from DLL?
Here is an example with Charcoal Dark Slate style:
Please disregard image orientation (before correction for TBitmap style containers).
Here is an example of the same application without styling (windows default):
Styled plugin is completely useless (slow when zooming, panning or any image change). Last example is with image orientation correction, but it's not relevant for this problem (just for info).
Here is a simple application. A form that has TImage, one TPanel and two speedbuttons on panel ("Load image" and "Execute plugin").
Here is an OnClick event for "Load image" button:
//---------------------------------------------------------------------------
void __fastcall TfrmSimple::SpeedButton1Click(TObject *Sender)
{
// load BMP in Image1
Image1->Picture->LoadFromFile("974-1.bmp");
// set our bitmap to pspiHost - we know that it's 24 bit bgr, no alpha, so we know the TImgType
int w, h;
srcImage = Image1->Picture->Bitmap;
TImgType type = PSPI_IMG_TYPE_BGR;
w = srcImage->Width;
h = srcImage->Height;
// let's say we don't know if TBitmap has contiguous buffer, so we'll add scanlines one by one
pspiStartImageSL(type, w, h);
for (int i = 0; i < h; i++)
pspiAddImageSL(srcImage->ScanLine[i]);
pspiFinishImageSL(); // done
}
In this example, scanlines are "send" to pspiHost.dll one by one, so there are three API calls.
Here is OnClick event for "Execute plugin" button:
//---------------------------------------------------------------------------
void __fastcall TfrmSimple::SpeedButton2Click(TObject *Sender)
{
// let's deal with filter
if (srcImage->Width < 2 || srcImage->Height < 2)
return;
// some 8bf filter for testing
String filter = "curves3 (32 bits).8bf";
// load filter
if (pspiPlugInLoad(filter.c_str()) == 0)
{
void *FP = DisableTaskWindows((HWND)(this->Handle)); // so that plugin window stays on top like modal (required for some filters)
int rc;
// execute filter
try {
rc = pspiPlugInExecute((HWND)(this->Handle));
} catch (...) {
rc = -1;
}
EnableTaskWindows(FP); // back to normal
Image1->Refresh();
if (rc != 0)
{
// error executing
}
}
else
{
// error loading -> plugin not loaded
}
}
There are two API calls, load filter and execute filter. That's all.
The architecture is quite simple: Application -> pspiHost.dll -> 8bf filter (which is again DLL). Application appearance affects plugin window. Question is how to disable such behaviour?

Force QCompleter to reappear if user selects directory

I have a dialog where user selects file(s). I added QCompleter to the line edit, which automatically suggests next file name:
However if user clicks on file, the suggestions disappear:
I want them to reappear if directory is selected and display the files in that directory. I tried to do this inside the QLineEdit::textChanged signal. I connected it to such slot:
void ImportFromExcelDialog::pathChanged( const QString& path )
if(path.length()>0) {
QFileInfo info(path);
if( info.exists() && info.isFile() && info.isReadable() ) {
// File selected, do stuff with it
}
else {
// If a directory
if((info.exists() && info.isDir())) {
if(!path.endsWith("/"))
ui->fileLineEdit->setText(path + "/");
// Assume QCompleter* completer_; which is set in constructor
if(completer_!=nullptr)
completer_->complete();
}
}
}
}
The problem is that calling complete() shows the old list of files, the one for parent directory:
I can click telemetrie as many times as I want and the display won't change.
So how to force QCompleter to reappear and handle the new value of the text field?

Enable button function inside backgroundWorker

I am using windows form application to create gui. I have create a form with several button. The functionality of the first button called button1 is to read a video from hard disk and display it to a picturebox. The last line of button1 code is to enable another button:
button2->Enabled = true;
Button1 code is inside a backgroundworker. The result of this, it works fine, however it doesnt enable the button2. Is there issue using button properties inside backgroundworker?
You have to use BeginInvoke method and use Action delegate because backgroundworker DoWork doesn't modify UI.
private:
void DoWork(Object^ /*sender*/, EventArgs^ /*e*/ )
{
// some code
button2->BeginInvoke(gcnew Action(this, &MyForm::ModifyButton) );
}
void ModifyButton()
{
button2->Enabled = true;
}

How to detect QTableWidget scroll source (code itself/user (wheel)/user (scrollbar))?

I'm writing a program using Qt 4.8 that displays a table (QTableWidget) filled with filenames and file's params. First an user adds files to the list and then clicks process. The code itself updates the contents of the table with simple progress description. I want the table by default to be scrolled automatically to show the last processed file and that code is ready.
If I want to scroll it by hand the widget is being scrolled automatically as soon as something changes moving the viewport to the last element. I want to be able to override the automated scroll if I detect that it was the user who wanted to change view.
This behavior can be seen in many terminal emulator programs. When there's a new line added the view is scrolled but when user forces the terminal to see some previous lines the terminal does not try to scroll down.
How could I do that?
Solution:
I created an object which filters event processed by my QTableWidget and QScrollBar embedded inside. If I spot the event that should turn off automatic scrolling I just set a flag and stop scrolling view if that flag is set.
Everything is implemented inside tableController class. Here are parts of three crucial methods.
bool tableController::eventFilter(QObject* object, QEvent* event)
{
switch (event->type())
{
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::Wheel:
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
_autoScrollEnabled = false;
default:
break;
}
return QObject::eventFilter(object, event);
}
void tableController::changeFile(int idx)
{
[...]
if (_autoScrollEnabled)
{
QTableWidgetItem* s = _table.item(_engine.getLastProcessed(), 1);
_table.scrollToItem(s);
}
[...]
}
void tableController::tableController()
{
[...]
_autoScrollEnabled = true;
_table.installEventFilter(this);
_table.verticalTableScrollbar()->installEventFilter(this);
[...]
}
Thanks for all the help. I hope somebody will find it useful :)
Subclass QTableWidget and overload its wheelEvent. You can use the parameters of the supplied QWheelEvent object in order to determine if the user scrolled up or down.
Then use a simple boolean flag which is set (or reset) in your wheelEvent override. The method which is responsible for calling scrollToBottom() should then consider this boolean flag.
You will have to find a way to figure out when to set or reset that flag, e.g. always set it when the user scrolls up and reset it when the user scrolls down and the currently displayed area is at the bottom.
connect(_table->view()->verticalScrollBar(), &QAbstractSlider::actionTriggered, this, [this](int) {
_autoScrollEnabled = false;
});

QPrintPreviewDialog incorrect preview

Using QPrintPreviewDialog to preview the print, I use the following code
QPrinter printer;
printer.setResolution(QPrinter::HighResolution);
printer.setPaperSize(QPrinter::A4);
printer.setOrientation(QPrinter::Portrait);
QPrintPreviewDialog *pd = new QPrintPreviewDialog(&printer);
connect(pd,SIGNAL(paintRequested(QPrinter*)),this,SLOT(print(QPrinter*)));
pd->exec();
void Class::print(QPrinter *p)
{
QTextEdit *ted = new QTextEdit;
ted->insertHtml("<center><img src='"+QString(":/img/logo.png")+"' width='90' height='72'/><b><font size='9'>Logo Text</font></b></center>");
ted->document()->print(p);
}
On pushing the print button, this dialog appears:
As you can see the content is spread all over the page.
Then I click the page setup button on the preview dialog and this appears:
without changing anything, I click OK and then the preview becomes correct:
The question is that how to correct the preview by code?
Use QTextDocument instead of a QTextEdit, the latter is a widget, which makes the output depend on resizing.
Add a QPageSetupDialog to show before preview.
I had the same issue. Apparently, pressing the OK button of the page setup dialog changes the resolution. To fix this, I change the resolution back in the method which calculates the print preview:
dialog = QPrintPreviewDialog()
dialog.paintRequested.connect(self.print)
dialog.exec_()
def print(self, printer):
printer.setResolution(300)
painter = QPainter()
painter.begin(printer)
...

Resources