PDA

View Full Version : Problem with moving QWinWidget



jazuju
30th August 2011, 13:18
Hi,

I'm using QWinWidget from Qt's Windows Migration Toolkit to extend my old MFC application with Qt widgets. Because I wanted to keep the code as clean as possible, I created a template class that behaves as a placeholder for the different Qt widgets. Code:



#ifndef QPlaceHolder_H
#define QPlaceHolder_H

#include <QWinWidget>
#include <QHBoxLayout>

template <typename QWidgetType>
class QPlaceHolder : public QWinWidget {
public:
QPlaceHolder(CWnd* parentWnd) : QWinWidget(parentWnd)
{
myWidget = new QWidgetType(this);
QHBoxLayout* hbox = new QHBoxLayout(this);
hbox->setContentsMargins(0, 0, 0, 0);
hbox->addWidget(myWidget);
myWidget->show();
QWinWidget::show();

}

~QPlaceHolder ()
{
}

QWidgetType* widget()
{
return myWidget;
}

private:
QWidgetType* myWidget;
};

#endif //QPlaceHolder_H


So example use of my code would be e.g.



// somewhere in my main MFC window code
QPlaceHolder<QLabel>* label = new QPlaceHolder<QLabel>(this);
label->widget()->setText("Hello!");
label->move(200, 100); //moving command must be done for the base widget (...right?)
//delete label; //this would delete also the QLabel object


The problem is:
Running this code makes the label visible, BUT it can't be moved (it stays in location (0, 0). I've tried different solutions without success. Do you have any suggestions that I could try?

And second problem is:
I'd like to use the graphical UI editor of MFC framework to locate the Qt widgets. Any suggestions how to achieve this?

Also any other comments/improvements are highly appreciated!

Big thanks!
Rgs,
jazuju

high_flyer
31st August 2011, 10:13
I don't think you can call move on a "top level" (from Qt perspective relative to your MFC GUI) since that is the domain of MFC.
Unless you make it really top level (i.e no parent).
You can move your widget in bounds of your QWinWidget, but for moving your QWinWidget you will probably have to write MFC code.

jazuju
13th September 2011, 15:22
Hi,

sorry for late response :)

Thanks for the response - I think you're right: moving the QWinWidget has to be done with MFC code. However, I'm not very familiar with MFC or Win32 programming and thus my solutions have not worked so far.

Here's an example from my latest non-functional solution. Do you think I'm on a right path? Suggestions?



//in QPlaceHolder implementation (subclass of QWinWidget)
void move(int x, int y)
{
HWND wnd = QWidget::winId();
HWND pwnd = GetParent(wnd);
POINT wndpoint;
wndpoint.x = x;
wndpoint.y = y;
ScreenToClient(pwnd, &wndpoint);
RECT wndrect;
GetWindowRect(wnd, &wndrect);
MoveWindow(wnd, wndpoint.x, wndpoint.y,
wndrect.right-wndrect.left, wndrect.bottom-wndrect.top, true);
UpdateWindow(pwnd);
}

wysota
13th September 2011, 16:30
Why are you embedding MFC code in a Qt app?

jazuju
14th September 2011, 11:22
I'm trying to extend an existing MFC app with Qt widgets. I'm doing this by using the QWinWidget from Windows Migration Toolkit as a placeholder for the QWidgets. QWinWidget itself is a QWidget that can be placed as a child of CWnd. The problem is, I haven't found a way to move the QWinWidget.

wysota
14th September 2011, 13:20
Maybe it's easier to just rewrite MFC code in Qt? Remember that you can use all regular WinAPI calls in a Qt app, you just need to rewrite MFC-specific parts.

jazuju
14th September 2011, 13:58
Maybe it's easier to just rewrite MFC code in Qt?

In our case that's not practical because our software has >200k rows of MFC code and immediate transfer to Qt would mean a huge work (and risk). So we're trying to replace the program little by little with Qt code and hopefully eventually move entirely into Qt. And I think that's a really appealing way to go. :)

wysota
14th September 2011, 16:06
I'm sure it is not >200k lines of MFC code, I bet only a couple hundred of lines are MFC-specific. You need to remember that MFC has a different philosophy than Qt so if you just stuff MFC controls into a Qt app, you're in practice dealing with two totally separate applications that use a different approach. You should start your work with small steps that make big differences and then replace code that is too hard to adapt. If you can't move controls written in MFC then either don't move them or replace those particular windows with Qt code or write MFC code that performs the work (as high_flyer suggested).

jazuju
15th September 2011, 12:36
I'm sure it is not >200k lines of MFC code, I bet only a couple hundred of lines are MFC-specific.

Well, maybe the truth lies somewhere between those :P Thanks for your advice! Despite the cons of mixing MFC and Qt, the pros are much more remarkable in our situation. For example, our software uses lot of customized MFC controls that are tedious to reimplement in Qt. Thus, with all respect to your advice, we're trying to go the way I described.

I've had some progress. With the following code the QPlaceHolder widget (subclass of QWinWidget) can alse be moved as a child of CWnd.




#ifndef QPlaceHolder_H
#define QPlaceHolder_H

#include <QWinWidget>
#include <QHBoxLayout>
#include <QMessageBox>

template <typename QWidgetType>
class QPlaceHolder : public QWinWidget {
public:
QPlaceHolder(CWnd* parentWnd) : QWinWidget(parentWnd)
{
myWidget = new QWidgetType(this);
QHBoxLayout* hbox = new QHBoxLayout(this);
hbox->setContentsMargins(0, 0, 0, 0);
hbox->addWidget(myWidget);
myWidget->show();
QWinWidget::show();

}



void move(int x, int y)
{
HWND wnd = QWidget::winId();
HWND parentwnd = GetParent(wnd);
QMessageBox::information(NULL, "Before moving QPlaceHolder", QString("curx=%1, cury=%2, curwidth=%3, curheight=%4").arg(this->pos().x()).arg(this->pos().y()).arg(this->width()).arg(this->height()));
RECT parentRect;
RECT myRect;
GetWindowRect(parentwnd, &parentRect);
GetWindowRect(wnd, &myRect);
POINT topleft;
topleft.x = parentRect.left + x;
topleft.y = parentRect.top + y;
ScreenToClient(parentwnd, &topleft);
int width = myRect.right - myRect.left;
int height = myRect.bottom - myRect.top;
MoveWindow(wnd, topleft.x, topleft.y, width, height, TRUE);
UpdateWindow(wnd);
}


QWidgetType* widget()
{
return myWidget;
}

private:
QWidgetType* myWidget;
};


#endif //QPlaceHolder_H





There's still a problem that I can't resolve: moving the widgets is working only if the line 28 (QMessageBox::information....) is executed. If I comment that row out, moving doesn't work anymore. Weird. Do you have any clue what's going on here?

wysota
15th September 2011, 12:45
Does it work if you replace the line with QApplication::processEvents()?

high_flyer
15th September 2011, 12:46
It sounds to me that the popping up of the information message box forces an update on your widget, which without it doesn't happen, as I also don't see it in your code (Qt side, not MFC).
Try calling myWidget->upate() at the end of move(), see if it helps.

EDIT:
@wasota: was also my first thought, but it would mean that the event loop is busy, and I don't see a reason why it should be, based on the code he posted so far.

wysota
15th September 2011, 12:50
It doesn't have to mean it is busy, some attributes might just have improper values for the move to succeed. However I think the situation is strictly MFC-specific and Qt has little to do with this so you might be right.

jazuju
15th September 2011, 13:50
Hooray! Putting
QApplication::processEvents() in the beginning of move() made the magic and now everything seems to work. Big thanks for you, guys!

I also tried the update() method but that didn't help. So what do you think - was this problem caused by not-yet-initialized Qt widgets?

high_flyer
15th September 2011, 14:11
some attributes might just have improper values for the move to succeed.
So you mean, that the events that bring about the correct state first need to be processed before the move is completed, is that it?
Hmm... seems to makes sense, as the information dialog is modal, so the event loop returns and does a bit work right after the dialog is dismissed, which is not happening when the dialog is not popped...
Or did you mean something else?

wysota
15th September 2011, 14:51
Something like that. I don't know how the MFC-migration framework works, it is just a guess.