-
Hi everyone.
I have a CDialog with SFML RenderWindow created in a separated class. Everything is working OK, with the exception of two things.
1. Because I want to keep the CDialog events instead of the SFML I have problem that I loose the focus for mouse wheel event. I can use the mouse and the buttons, but the mouse wheel event is not triggered until I use the right button and click on the menu on the Windows bar where the programs icon is. And after I click outside of the program I loose the focus again. Is there a workaround this?
2. How can I resize SFML window. I use custom events to resize the CDialog window using SetWindowPos().
-
Any one? ;D ;D ;D
-
I highly doubt anyone is still seriously working with MFC...
-
Using MFC is not the problem here.
setSize() is not doing anything on the RenderWindow when set. I can't make it change.
The focus is also strange, because I can use all othe mouse functions, except the mouse wheel.
-
setSize() works only on top-level windows.
-
So there is no way to resize the RenderWindow?
-
If it is embedded inside a MFC control, you can resize the MFC control itself.
-
I am doing that, but it has no effect. I am passing a HWND from the CDialog in order to create the RenderWindow. I then resize the CDialog window and pass the size to the RenderWindow's setSize() too. The result it that the CDialog is resized, but the drawing "stops" in the old size of the RenderWindow.
-
This is not supposed to happen, the SFML window should automatically adjust to the new size.
-
Well its either not working correctly or I am not doing it correctly. I will post a pseudo code tomorrow to show you what I am doing.
-
... I will post a pseudo code tomorrow to show you what I am doing.
Do better than that and post a "complete and minimal" example that shows the problem.
See these links:
https://github.com/SFML/SFML/wiki/FAQ#tr-grl-minimal
http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368
-
Wouldn't that will be a bit hard, because the problem is exactly in the use of CDialog and SFML, so it can't be as minimal as described in the links.
-
There's always a minimal code that reproduces the problem.
If all you need is a CDialog with a sf::RenderWindow inside, and call SetWindowPos on it, you won't need thousands of lines of code.
-
Of course not, that is why I said I will post a pseudo code that will include only the relative parts of the program that are in connection to the problem. ;)
-
Here is the code sample, I am not including the CDialog in its full minimal form because it will take too much space, but I can create a minimalistic project and uploaded for anyone who wants to test it.
CDialog:
This is the defined _SFML variable
SFML_CL _SFML
This is the pseudo code of the main CDialog class
BOOL CClassTestsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
FIRSTRESIZE = true;
HWND hWND = GetSafeHwnd();
_SFML.Initialize(hWND);
return TRUE;
}
void CClassTestsDlg::OnSize(UINT nType, int cx, int cy){
if(FIRSTRESIZE){
SetWindowPos(&CWnd::wndTopMost , 0, 0, 500, 500 ,SWP_SHOWWINDOW|SWP_NOZORDER );
FIRSTRESIZE = false;
}
CDialog::OnSize(nType, cx, cy);
}
void CClassTestDlg::ChangeSize()
{
SetWindowPos(&CWnd::wndTopMost ,0,0,700,700,SWP_SHOWWINDOW|SWP_NOZORDER);
}
SFML_CL:
#pragma once
#include <SFML/Graphics.hpp>
class SFML_CL
{
public:
SFML_CL(void);
virtual ~SFML_CL(void);
void Initialize(HWND hWnd);
void Render();
protected:
HWND hWND;
sf::RenderWindow *ttl2D;
sf::Font font;
COLORREF ColorBG;
};
SFML_CL::SFML_CL(void)
{
ttl2D = NULL;
ColorBG = RGB(90,90,90);
}
SFML_CL::~SFML_CL(void)
{
delete ttl2D;
}
void SFML_CL::Initialize(HWND hWnd)
{
hWND = hWnd;
sf::ContextSettings ws;
ws.antialiasingLevel = 8;
ttl2D = new sf::RenderWindow( hWND,ws );
ttl2D->setVerticalSyncEnabled(true);
font.loadFromFile("res/Arial.otf");
}
void SFML_CL::Render()
{
sf::Color color(GetRValue(ColorBG ),GetGValue(ColorBG ),GetBValue(ColorBG ),255);
ttl2D->clear(color);
sf::Text text;
text.setCharacterSize(13);
text.setColor(sf::Color::White);
text.setPosition(20,80);
CRect rect;
GetClientRect(hWND,rect);
CString fp;
fp.Format("%d (%d : %d %d %d %d)",ttl2D->getSize().x,ttl2D->getSize().y,rect.left,rect.top,rect.Width(),rect.Height());
text.setString(fp.GetBuffer());
fp.ReleaseBuffer();
text.setPosition(20,150);
ttl2D->draw(text);
ttl2D->display();
}
This will result in a constant values for ttl2D->getSize().x and ttl2D->getSize().y, but the rect coordinates will be updated accordingly
-
You didn't understand the idea behind the complete and minimal code ;)
Please read the given links carefully.
-
I did, but should I also post all 13 files, plus the .sln file? Because in order to have a working complete and minimal code you would need all of these files ??? ;D
I can't modify the code to be in main(), because that will remove the problem part of the project, which is the MFC CDialog with SFML.
I can post all of the files, but I though it would be easy to understand to simply upload the demo project.
-
I did
I don't think so. The explanations clearly state that there's no point trying to show small parts of your code, because they are incomplete, or the whole thing, because it will be too much. You must write a new code that only reproduces the problem, and nothing else. We don't care about your original project.
Can't you simply declare a CDialog, the corresponding sf::RenderWindow and call SetWindowPos on it? Why would it require more than a few lines of code?
-
Because it is a CDialog project. Than means that in order to have just a simple Window, you need:
Resource.h
SFML_TEST.h
SFML_TESTDlg.h
stdafx.h
targetver.h
SFML_TEST.rc
SFML_TEST.rc2
SFML_TEST.cpp
SFML_TESTDlg.cpp
stdafx.cpp
All these files are generated by VS when you open a new, clean CDilaog project. On top of that is my simple SFML_CL class.
I can't simply convert that in a few lines of code or in a simple main(), simply because it will not work. And you will not see the problem as it is now.
The explanations states
It is important that:
the code is complete, so people can test it
the code is as simple as possible, the best is one main() with all the code inside -- people don't want to setup a complex project just to test your code
the code reproduces the initial problem
the application doesn't depend on external resource files (unless it's related to the problem)
Well if some can explain how to convert a MFC CDialog project in a single simple file I would more then happy to do it. Again the problem is in the interconnection of MFC and SFML, so without the minimal CDilaog project files I can't show you anything useful that will help my problem.
I am really not making an argument here, just want to explain that I can't do what you what from me via a simple 20 lines program.
-
I understand. I had forgotten that MFC was such a hell...
Well, from what you showed previously, everything looks ok. But it will be hard to investigate further, since we can't test your code. Can't you simply switch to a more modern GUI library? You'll save yourself a lot of troubles :P
-
Well I am looking at Qt, in order to fully leave MFC, the problem is that project so far is more then 50 classes with average of 2000 - 3000 lines per class. Sure most of them are not related to MFC, except the CString and CArray used in them, but it will still take me too much time to port it at once.
The problem I am having with MFC is that I draw heavily on the screen. I have CArrays with more then 30000 elements on the screen at any one time. So in MFC using GDI it is ok, I get 40-60 fps, but I don't have all the bells and whistle OpenGL and Direct2D. Direct2D's performance is just awful, 15fps.
With SFML I get 70-80 and have all the great stuff like anti-aliasing, alpha and so on so it would have worked just fine, until I port everything to Qt, except the few issues I am having now. I also want to say that I use my one draw interface, so I don't use MFC for the Windows forms or anything like that. I will use SFML the same way, drawing my own windows, buttons and so on.
No to the problem, I can upload on my server a zip with a small demo program with the same problem that I have explain in the first post, if some would want to spend his free time to check it.
-
Here is the link to the VS2008 project
https://app.box.com/s/b7s8n0z2lvw4un82wa1l
It is a simple CDialog Window that draws a rectangle using SFML. When you click with the mouse (strangely it requires to click to work) the window is resized and it's position is changed. You can see that the drawn rectangle gets cut in the window. So I am guessing the SFML RenderWindow is not resized.
-
is more then 50 classes with average of 2000 - 3000 lines per class.
Are you reinventing the wheel a hundred times or why do you have 50 classes and they still have 2000-3000 lines of code? If you class exceeds 1000 lines, it's a big indicator that your code needs a heavy refactoring. ;)
-
Because it is a aviation program generating flight envelope profiles and trajectory predictions. It is not that simple as you think. ;) ;) ;)
-
As I can see that this may not be overcome I have some questions.
1. I am looking at Qt and it looks quite interesting so I may switch to it, but can I have the following thing:
I need SFML as a moving map only, I don't need it for the UI it self, just to draw with SFML inside of one window. Is this possible? I can draw my own UI (I am doing that in MFC anyway), but Qt can make it easier if I can use it for the UI and SFML just for the moving map on the main window.
-
Yes, you can easily embed a sf::RenderWindow into a QWidget.
-
Thanks for the fast reply. Is this tutorial still valid for SFML 2.1 and Qt 5.2 http://www.sfml-dev.org/tutorials/1.6/graphics-qt.php?
-
As far as I know, yes. Of course you have to adapt the naming of SFML functions.
-
Warning that Qt can't receive any event from SFML. except the mouse click event.
http://www.qtcentre.org/threads/52568-Qt5-native-messages-not-propogated
-
If you use Qt, use Qt events ;)
-
Thanks, I am aware of the problem, but I can simply manually resend toSFML, don't I?
-
Well I have a small problem with Qt and SFML. The loadFromFile() for a font is always false and when I use that font, it of course crashed the program.
Any tips? The path to the font is correct. I get the same result even when I type in the full path.
I have included the .dll files in the root folder of the project. Is this correct or they have to be somewhere else too.
-
The standard output should give more details about the failure.
-
Well I am having a nightmare with linking problems for SFML. I simply can't figure this out.
This is the .pro file
#-------------------------------------------------
#
# Project created by QtCreator 2014-03-31T11:57:25
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Test2
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
global_objects.cpp \
MyCanvas.cpp \
QSFMLCanvas.cpp
HEADERS += mainwindow.h \
global_objects.h \
MyCanvas.h \
QSFMLCanvas.h
FORMS += mainwindow.ui
LIBS += -LC:/SFML64/lib
CONFIG(release, debug|release): LIBS += -lsfml-audio -lsfml-graphics -lsfml-main -lsfml-network -lsfml-window -lsfml-system
CONFIG(debug, debug|release): LIBS += -lsfml-audio-d -lsfml-graphics-d -lsfml-main-d -lsfml-network-d -lsfml-window-d -lsfml-system-d
INCLUDEPATH += C:/SFML64/include
I have a linker error for everything connected with SFML (MyCanvas.obj:-1: error: LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl sf::Clock::Clock(void)" (__imp_??0Clock@sf@@QEAA@XZ) referenced in function "public: __cdecl MyCanvas::MyCanvas(class QWidget *,class QPoint const &,class QSize const &)" (??0MyCanvas@@QEAA@PEAVQWidget@@AEBVQPoint@@AEBVQSize@@@Z)
like that)
I was working OK for a while, then I replaced the SFML files again and now I have that.
-
then I replaced the SFML files again
Replaced with what?
-
With the Visual C++ 11 (2012) - 64 bits files. They were the same before, but because I wasn't sure I overwrite them just to be safe.
-
And are you sure that you're using a Visual C++ build of Qt? The default is MinGW.
-
Yes.
I use Qt 5.2.1 for Windows 64-bit (VS 2012, OpenGL, 553 MB) .
-
Well after full reinstall of Qt and SFML, everything is no OK, the font is loaded correctly 8) ;D ;D ;D
-
OK guys,
After some days of work I have move the test project from MFC to Qt. But I still have the same problem when I re-size the window. The problem is that the SFML window itself (which is embedded in the QWidget) is re-sizing with it, but the content gets cut as thou the view port is still with the original size of the window when it was created. Here is a picture, the rect should be enlarged, but should be square. You can see that the left part (red ) is cut and is not seen.
https://drive.google.com/file/d/0BwLPPjKzXAi1SVRoTmFVZmdORjA/edit?usp=sharing (https://drive.google.com/file/d/0BwLPPjKzXAi1SVRoTmFVZmdORjA/edit?usp=sharing)
Any ideas?
-
I have to reset the view every time I recreate a window in my SFML program, which has no MFC or Qt or anything attached to it. Are you resetting yours?
-
;D Nope, how to do that?
-
http://www.sfml-dev.org/tutorials/2.1/graphics-view.php
Though I only had to do that because I was using non-default views, so maybe you're having a different issue. Still, setting an explicit view after resizing can't hurt.
-
Is it a sf::Window or a sf::RenderWindow?
-
It is a sf:RenderWindow
-
So do I have to reset the view even if I haven't defined one?
-
No, you don't have to do anything, it should work. Everything that works for a standalone sf::RenderWindow should work too for an embedded one.
-
So what could the problem be? I can see that the window itself is resizing (the clear color is resized OK) but for some reason all is cropped if outside of the original size of the window.
-
Do you get a sf::Event::Resized event?
-
Well I am implementing this tutorial http://sfml-dev.org/tutorials/1.6/graphics-qt.php (http://sfml-dev.org/tutorials/1.6/graphics-qt.php),
and I am getting the resize event in the MyCanvas class.
I have to say that the MyCanvas is itself called as variable in a Qt Widget, thus embedding the MyCanvas (SFML).
-
I am getting the resize event
If you get the sf::Event::Resized event when the widget is resized, then the sf::RenderWindow has it too, and your problem shouldn't happen :-\
-
I will make a small demo and will post it here (yes minimal and complete code ::) :P ;) ;D) so you can test and if possible find the solution for it.
-
OK, maybe there is something wrong in the implementation that I did.
I am receiving the resize event in the MyCanvas, but how can I be sure that I am also resizing QSFMLCanvas which is the base class of MyCanvas? Because what I am thinking is that MyCanvas is resizing, but the event is not send to QSFMLCanvas too, so it stays the same size.
-
It's the SFML window that gives you this event, so it knows it before you ;)
-
Then I am out of ideas :D
-
Sorry but can you explain a bit more in details. Because I am resizing the MyCanvas manually when I resize the main window. So basically I am resizing the SFMLCanvas widget. Does that means the RenderWindow also gets that event?
-
If your SFML event loop gives you a sf::Event::Resized event when you resize the canvas, then for sure the RenderWindow gets it (because you got the event from it).
-
Well I am now sure that the SFML window is resing along with the Qt widget, so the problem is somewhere else. When I check the viewport size I get 1000/1000, is this value real pixels or just indicating 100% from the SFML window. Because it stays constant during the resize
-
I know nothing about all this Qt stuff, but...
is this value real pixels or just indicating 100%
Viewports use floats between 0 and 1, with {0,0,1,1} representing the entire window (whatever its pixel size may be).
The view itself has a size measured in pixels (roughly speaking).
I also noticed that the default constructor for sf::View() seems to call reset(FloatRect(0, 0, 1000, 1000)); so maybe that's where your 1000s are coming from.
-
Well I spoke too soon. It seems that the SFML windows IS NOT resized after all
I did to test it this time
void MyCanvas::resizeEvent(QResizeEvent *event)
{
qDebug() << "RESIZED Widget" << event->size().width() << event->size().height();
setSize(sf::Vector2u(event->size().width(),event->size().height()));
qDebug() << "RESIZED SFML" << getSize().x << getSize().y;
}
which is resulting in this
RESIZED QWidget 502 470
RESIZED SFML 502 470
RESIZED QWidget 504 471
RESIZED SFML 502 470
RESIZED QWidget 504 471
RESIZED SFML 502 470
RESIZED QWidget 521 481
RESIZED SFML 502 470
RESIZED QWidget 521 481
RESIZED SFML 502 470
RESIZED QWidget 535 487
RESIZED SFML 502 470
RESIZED QWidget 535 487
RESIZED SFML 502 470
RESIZED QWidget 546 492
RESIZED SFML 502 470
So where would the problem be?
-
I think this is exactly the same issue http://en.sfml-dev.org/forums/index.php?topic=12952.15. So how to change the videomode after the window has been created?
-
I'm pretty sure you have to create() again to change the video mode.
There is a setSize() method, but I have no idea if that does what you need in this context.
-
Can we please be absolutely clear about one point? You kept repeating that you got the right sf::Event::Resized events whenever you resized the widget. Is that really true? I really mean the sf::Event::Resized SFML event, not the QResizeEvent from Qt. If you get them, then it's absolutely impossible that your sf::RenderWindow size never changes...
By the way, you should write a complete and minimal example that reproduces the problem.
-
Here is the code
sfmlcanvas.h
#ifndef QSFMLCANVAS_H
#define QSFMLCANVAS_H
#include <QWidget>
#include <SFML/Graphics.hpp>
#include <QTimer>
class QSFMLCanvas : public QWidget, public sf::RenderWindow
{
//Q_OBJECT
public:
explicit QSFMLCanvas(QWidget *parent, const QPoint& Position, const QSize& Size, unsigned int FrameTime = 1);
virtual void showEvent(QShowEvent*);
virtual QPaintEngine* paintEngine() const;
virtual void paintEvent(QPaintEvent*);
virtual ~QSFMLCanvas();
virtual void OnInit();
virtual void OnUpdate();
private:
QTimer myTimer;
bool myInitialized;
HWND _hWND;
protected:
virtual void resizeEvent(QResizeEvent * event );
};
#endif // QSFMLCANVAS_H
sfmlcanvas.cpp
void QSFMLCanvas::showEvent(QShowEvent*)
{
if (!myInitialized)
{
// Under X11, we need to flush the commands sent to the server to ensure that
// SFML will get an updated view of the windows
#ifdef Q_WS_X11
//XFlush(QX11Info::display());
#endif
// Create the SFML window with the widget handle
_hWND = sf::WindowHandle( winId());
RenderWindow::create(_hWND);
// Let the derived class do its specific stuff
OnInit();
// Setup the timer to trigger a refresh at specified framerate
connect(&myTimer, SIGNAL(timeout()), this, SLOT(repaint()));
myTimer.start();
myInitialized = true;
}
}
QPaintEngine* QSFMLCanvas::paintEngine() const
{
return 0;
}
void QSFMLCanvas::paintEvent(QPaintEvent*)
{
// Let the derived class do its specific stuff
OnUpdate();
// Display on screen
display();
}
void QSFMLCanvas::OnInit() {}
void QSFMLCanvas::OnUpdate() {}
void QSFMLCanvas::resizeEvent(QResizeEvent *event){}
mycanvas.h
#ifndef MYCANVAS_H
#define MYCANVAS_H
#include "qsfmlcanvas.h"
#include <SFML/Graphics.hpp>
class MyCanvas : public QSFMLCanvas
{
public :
MyCanvas(QWidget* Parent, const QPoint& Position, const QSize& Size);
void OnInit();
void OnUpdate();
void resizeEvent(QResizeEvent *event);
private :
sf::Clock myClock;
sf::RectangleShape rect;
sf::Font font;
sf::Text text;
};
#endif // MYCANVAS_H
mycanvas.cpp
#include "mycanvas.h"
#include <iostream>
#include <string>
#include <QDir>
#include <QWheelEvent>
#include <qdebug.h>
MyCanvas::MyCanvas(QWidget* Parent, const QPoint& Position, const QSize& Size) : QSFMLCanvas(Parent, Position, Size)
{
}
void MyCanvas::OnInit()
{
myClock.restart();
}
void MyCanvas::OnUpdate()
{
// Clear screen
clear(sf::Color(69, 78, 83));
sf::Font font;
font.loadFromFile("arial.ttf");
// Create a text
sf::Text text("hello", font);
text.setCharacterSize(30);
text.setStyle(sf::Text::Bold);
text.setColor(sf::Color::Red);
text.setPosition(width() - 100,height()/2);
// Draw it
draw(text);
myClock.restart();
}
void MyCanvas::resizeEvent(QResizeEvent *event)
{
qDebug() << "RESIZED SFML";
// setSize(sf::Vector2u(event->size().width(),event->size().height()));
QWidget::resizeEvent(event);
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include "MyCanvas.h"
class MainWindow : public QWidget
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
MyCanvas Canvas;
private:
protected:
void resizeEvent( QResizeEvent * event);
void paintEvent(QPaintEvent *event);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QPainter>
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent),
Canvas(this,QPoint(5,20),QSize(width() - 20,height() - 40))
{
//setWindowFlags ( Qt :: FramelessWindowHint);
}
MainWindow::~MainWindow()
{
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
Canvas.move( 5, 22);
Canvas.resize(width() - 10,height() - 44);
}
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Just resize the window and you will see how the text disappear to the right.
-
Bump ;D ::)
-
Can you make a complete and minimal code as described here (http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368)?
-
I can't make more minimal code then this in order to reproduce the problem. ??? :-[
-
Well I overcome the problem for now, I delete the MyCanvas and recreate it again on end of resize. Not the best solution, but for now it works...
Now I have another problem. If I have a QDilaog or QWidget object in nonmodal on top of the SFML window I can't get back the focus of the mouse on that object. The focus stays on the SFML. Interesting that the mouse wheel works at is should be, but the other functions (mouse move/click) are never send to the object. Always stay on the SFML.
Any solutions on that?
-
This is probably another thing we can't even begin to help you with unless you provide a complete and minimal example, BUT it's known that SFML 2.1 had some window focus problems, so if that's the version you're using then you could try building from the latest Github source instead.
-
Thanks will try compile the latest.
-
Well what do you know, the latest beta worked :D Thanks Ixrec