I'm creating simple c++ application with user interface. I have written own classes with needed mechanics, and now I must display some of its components using wxWidgets. MyApp contains objects of that classes, but they are also needed in MyFrame when handling events. It would be much more comfortable without passing pointers to that objects to MyFrame and implement everything in MyApp::OnInit function. Is that possible?
// should contain informations about game state, players, gameboard, etc
class MyApp : public wxApp {
GameBoard gb;
Player player;
bool lightTheme;
public:
virtual bool OnInit();
};
// should contain only window layout, button events, etc
class MyFrame : public wxFrame {
GameBoard *gb;
Player *player;
bool *lightTheme;
std::vector<wxStaticBitmap*> cardImages;
// some events here
void displayImages(wxGridSizer*);
public:
MyFrame(GameBoard*, Player*, bool*);
};
To answer your title question, you don't have to declare MyFrame and can just create and directly use wxFrame and use Bind() to connect the different event handlers. In all but the simplest situations, it's typically convenient to have a MyFrame class centralizing the data and event handlers for the window, but it is not required by any means.
If you decide to keep everything in MyApp instead, you may find wxGetApp() useful for accessing it from various places in your code.
Related
I have difficulty connecting to SLOTs defined in a different class. I have 2 classes - Computations and MainWindow. MainWindow is supposed to handle the GUI part of the program only and Computations handles the calculations. I am creating a calculator.
Basically, I want to understand how I can connect to SLOTs in the Computations Class from the MainWindow Class.
I guess you already checked the Qt Signals & Slots page. To implement what you want you need to have an instance of your class in the other one.
So for example in your MainWindow class, you can include the Computations class and create a member variable of it:
#include "computations.h"
class MainWindow : public QMainWindow
{
Q_ObBJECT
public:
//..
private:
Computations *_computation;
};
and then in the constructor of MainWindow after initializing the _computation object (_computation = new Computations();) you do the connections like this (works for Qt5):
QObject::connect(_computation, &Computations::somethingHappened, this, &MainWindow::doSomeGuiStuff);
QObject::connect(this, &MainWindow::guiThingHappened, _computation, &Computations::doSomeComputation);
depending on which way it should go.
I hope this helps.
This is another version how to use, I think can be easier to understand for beginners
You need define signal and slots in your classes.
Add to header of your class, for example signals to MainWindow, slots to Computations
public slots:
void something();
signals:
void something_happend();
Then, in anywhere, where you want use it, in your example in mainwindow.cpp, you need to connect signal and slot. Do this by QObject::connect :
QObject::connect(who_emit,SIGNAL(what_signal),who_receive,SLOT(what_slot))
Example:
mainwindow.h
signals:
void something_happend();
computations.h
public slots:
void something_happend();
mainwindow.cpp
Computations *c = new Computations(this);
QObject::connect(this,SIGNAL(something_happend()),c,SLOT(something()));
If you want to pass some arguments, SIGNAL and SLOT that you want to connect need have same types of arguments:
public slots:
void something(int c);
signals:
void something_happend(int c);
QObject::connect(this,SIGNAL(something_happend(int)),c,SLOT(something(int)));
Such connections belong at a level where both the UI and the controller (computation object) are available. Thus, either in the body of main, or in a class that composes that various elements of the application at a high level (such a class usually shouldn't derive from QApplication, though).
It is almost always too tight of a coupling if the UI class knows of the existence of the computation object, or is somehow tied to its details. I usually design the UI to have an interface composed of signals and slots of as generic a nature as practicable, and then tie it to one or more controller objects via signal/slot connections. I also leverage the property system to expose UI-relevant properties in a generic manner, often using viewmodel objects to interface a UI-agnostic controller to a concrete kind of a UI.
In your case, I'd suggest that neither MainWindow know of Computations, nor vice versa:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Computations comp;
MainWindow ui;
QObject::connect(&comp, ..., &ui, ...);
/* more connections here */
ui.show();
return app.exec();
}
For more concrete examples, see answer #1 or answer #2.
you need slots and signals because those work together, like this:
your file.h
public slots:
void start();
signals:
void levelChanged(int level);
implementing:
void MainBoard::start()
{
isStarted = true;
clearBoard();
emit levelChanged(1);
}
now you need to link a button
startButton = new QPushButton(tr("&Start"));
startButton->setFocusPolicy(Qt::NoFocus);
connect(startButton, &QPushButton::clicked, board, &MainBoard::start);
I have the following problem in Qt, I'm trying to make a chess-game and I'm encountering some problems:
In the class mainwindow I have the following function:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
scene = new ChessBoard;
QGraphicsView *view = new QGraphicsView(scene);
setCentralWidget(view);
connect(scene,SIGNAL(clicked(int,int)),this,SLOT(clicked(int,int)));
//!!!!!!!!!!
scene->setInitialPositions();
}
I have a variable scene, scene is an object of the class ChessBoard.
In the whole class mainwindow I can use the scene-variable to use functions declared in ChessBoard.
However, I have another class called game.
In game I have this function
void game::setStartBord() {
scene->setInitialPositions();
}
It simply needs to launch scene->setInitialPositions();
However, I don't have access to the 'scene-variable' there. I tried to inherit the ChessBoard and MainWindow class, tried to make scene global, but none really were a good solution.
How would I do that?
Full code is visibly here:
https://github.com/UA-Niel/chess
You can use signal and slot technique. Connect your game class object to scene object.
connect(game, &Game::mySignal, scene, &ChessBoard::setInitialPositions);
Define in your Game-Class the signal.
class Game .. {
..
signals:
void mySignal();
..
};
Then define setInitialPositions in your ChessBorard class in public slots.
class ChessBoard {
...
public slots:
<datatype> setInitialPositions();
};
Then use
emit mySignal(); from Game class
to execute setIntialPositions() in your ChessBoad class.
You need to design your code that you have access to both objects at some point. Mostly this is MainWindow because you intialize classes upon program start.
If your code does not depend on the intialized class.
You can simply do a new ChessBoard object in Game class
ChessBoard myObject;
myObject.setIntialPositions();
I tried to create a subclassed control for the first time, but I feel like I did something wrong. The control is a Button, which I placed in the designer. This is its class:
class TTTField : public CButton
{
public:
BEGIN_MSG_MAP_EX(TTTField)
MSG_WM_INITDIALOG(OnInitDialog);
END_MSG_MAP()
TTTField operator=(const CWindow& btn);
private:
const BOOL OnInitDialog(const CWindow wndFocus, const LPARAM lInitParam);
};
Nothing fancy so far.
However, I can't really achieve to receive windows messages in this control. This is bad, considering the main reason for trying to subclass a control was the fact that this should be a reusable class with reusable, custom Paint behaviour. I want to overwrite certain message handlers, while keeping those I didn't explicitely ask for to the usual CButton routine.
As you can see, I implemented a message map, but the messages are just not coming in.
This is how I tried to setup the instance of this class:
TTTField fld;
is a member variable of my main dialog class. In this class I added the following DDX_MAP:
BEGIN_DDX_MAP(TTTMainDialog)
DDX_CONTROL_HANDLE(IDC_BTN, fld)
END_DDX_MAP()
with IDC_BTN being the id of the button on the designer.
In the assignment operator overload for TTTField I have the following:
TTTField TTTField::operator=(const CWindow& btn)
{
Attach(btn);
return *this;
}
I feel like this operator overload might be the source of my problems, but I just can't manage to find a website which is properly explaining the whole topic without using code which seems outdated for like 20 years.
What am I doing wrong here? I am really lost right now.
The button class should be defined as follows:
class TTTField : public CWindowImpl<TTTField, CButton>
{
protected:
BEGIN_MSG_MAP_EX(TTTField)
MSG_WM_LBUTTONDOWN(OnLButtonDown)
END_MSG_MAP()
protected:
LRESULT OnLButtonDown(UINT, CPoint)
{
//Edit: this override is meant for testing the subclass only
//it's insufficient for handling button clicks
MessageBox(L"Testing override...");
return 0;
}
};
Override dialog box's OnInitDialog, call SubclassWindow to subclass the button:
class TTTMainDialog: public CDialogImpl<CMainDialog>
{
public:
enum { IDD = IDD_MYDIALOG };
BEGIN_MSG_MAP(TTTMainDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
END_MSG_MAP()
TTTField fld;
LRESULT OnInitDialog(UINT nMessage, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
fld.SubclassWindow(GetDlgItem(IDC_BTN));
return 0;
}
};
Edit, for initialization
class TTTField : public CWindowImpl<TTTField , CButton>
{
public:
void Create(CWindow *wnd, int id)
{
SubclassWindow(wnd->GetDlgItem(id));
//add initialization here
}
...
}
Then to create the button:
//fld.SubclassWindow(GetDlgItem(IDC_BTN));
fld.Create(this, IDC_BTN); //<== use this instead
Perhaps the best example, or at least one of, of subclassing a button is right in the sources of WTL, at the top of atlctrlx.h:
template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits>
class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
{
public:
DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
...
You will also file external resources on this class: Using WTL's CBitmapButton.
That's not to mention WTL's comment on doing the controls:
// These are wrapper classes for Windows standard and common controls.
// To implement a window based on a control, use following:
// Example: Implementing a window based on a list box
//
// class CMyListBox : CWindowImpl<CMyListBox, CListBox>
// {
// public:
// BEGIN_MSG_MAP(CMyListBox)
// // put your message handler entries here
// END_MSG_MAP()
// };
More examples of simple and sophisticated custom WTL controls can be found at viksoe.dk.
A confusing thing about WTL control extension is that basic classes like CButton, CComboBox are thin wrappers over standard controls. They mostly translate methods into messages to be sent. You can often easily cast instances of such classes to HWND and back.
Standard controls themselves offer a level of customization through support of notification messages.
When you subclass a control, you are adding functionality on your side which somehow needs to interoperate with stock implementation, and control classes are no longer thin wrappers. Hence, you inherit from CWindowImpl and not CButton directly. Next challenge is to specifically subclass: you need to have original window created and after that, having a HWND handle, you modify it to route the messages through your message map. This is where you need SubclassWindow method. That is, you have the control created, you look it up its handle, e.g. with GetDlgItem and then you subclass the window using your class instance SubclassWindow call. Or, alternatively you can create the control using your new class Create method in which case CreateWindow and association with your message map will be done for you.
Some, more complicated, implementations of custom controls will also want you to reflect notification messages from parent window to the controls, so that they could handle them within the same custom control class. This will typically require that you add a line REFLECT_NOTIFICATIONS in your dialog class message map (see this related question on this).
Reading books and topics on Cocos2dx everyone seems to be teaching it like so:
Create a class that inherits from CCLayer
Within that CCLayer class, instantiate a Static SCENE
Add layout to scene
Metaphorically, it is like the Egg creates its Parent. This seems backwards, non-intuitive. Why not just do this:
Create a class that inherits from CCScene (call it GameScene)
Create another class that inherits from CCLayer (call it GameLayer)
The GameScene class is a singleton (has a singleton member: static GameScene* scene)
Instantiate the GameLayer class within the GameScene class
The GameLayer class will have the usual suspects: UPDATE, INIT, etc. and the GameScene class with have INIT and it's static self-referencing member.
While this may seem like more work, it really isn't and logically makes more sense, furthermore, it affords the developer a place, to place SCENE specific logic, and LAYER specific logic.
Are there any issues doing it this way? Why are so many teaching it backwards?
EXAMPLE:
# GameScene
#ifndef __GameScene__
#define __GameScene__
#include "cocos2d.h"
using namespace cocos2d;
class GameScene : public cocos2d::CCScene
{
public:
~GameScene();
virtual bool init();
static GameScene* scene();
CREATE_FUNC(GameScene);
};
#endif /* defined(__GameScene__) */
#include "GameScene.h"
#include "GameLayer.h"
GameScene::~GameScene() {}
GameScene* GameScene::scene()
{
GameScene *scene = GameScene::create();
GameLayer *layer = GameLayer::create();
scene->addChild(layer);
return scene;
}
bool GameScene::init()
{
if (!CCScene::init()) return false;
return true;
}
# GameLayer
#ifndef __GAMELAYER_H__
#define __GAMELAYER_H__
#include "cocos2d.h"
using namespace cocos2d;
class GameLayer : public cocos2d::CCLayer
{
public:
~GameLayer();
virtual bool init();
virtual void draw();
void update(float dt);
CREATE_FUNC(GameLayer);
};
#endif // __GAMELAYER_H__
#include "GameLayer.h"
GameLayer::~GameLayer() {}
bool GameLayer::init()
{
if (!CCLayer::init())
return false;
this->schedule(schedule_selector(GameLayer::update));
return true;
}
void GameLayer::draw() {}
void GameLayer::update(float dt) {}
And finally within the AppDelegate CPP
bool AppDelegate::applicationDidFinishLaunching()
{
// initialize director
...
...
// Create a scene
GameScene *pScene = GameScene::scene();
// Run
pDirector->runWithScene(pScene);
return true;
}
I also have a thread on this topic on cocos2dx:
http://discuss.cocos2d-x.org/t/layer-instantiates-scene/18149/4
There is a confusion between base class names and the subclass names.
For instance in the cocos2d-x wiki they subclass from Layer (CCLayer) but they name this Layer subclass GameScene even though it isn't an actual scene, it's a layer. Further down they create the actual Scene (CCScene) instance with the call to createScene, which I assume returns a generic Scene instance with the GameScene instance added to the scene:
auto scene = GameScene::createScene();
Director::getInstance()->replaceScene(scene);
So you do end up with the following hierarchy:
Scene
Layer (custom class: GameScene)
Nodes...
Now the origin of this weird naming philosophy is simply that it has been going around in the cocos2d community for ages. In very early cocos2d-iphone project templates you had a HelloWorldScene class that inherited from CCLayer. It contained a class method scene that created an instance of CCScene, created a HelloWorldScene instance and added it to the generic scene instance before returning it.
So basically this is simply a confusion due to badly named subclasses in project templates, tutorials and books. Against all rational thought the "tradition" prevailed in cocos2d-x. In cocos2d-iphone this was eventually fixed (in v2.x I believe) by renaming the template class to HelloWorldLayer.
Rodger Engelbert author of Cocos2d-x by Example, Beginners Guide responded to this question via email.
Hi Jason,
There is no need to follow the strategy used in the template. In fact
I don't know anyone who does it outside the Cocos2d-x group and I only
ever used it in the examples for the book for consistency.
A Scene is unique, and it's what the director requires to run. It's
possible to have two scenes running during transitions, but otherwise
a scene is structurally treated as One block in your architecture. You
may or may not organize your project into multiple blocks, but you
will need at least one.
But you're free to do it in any way you wish. You might use scenes
more prominently, as some developers do or use one only, for the sake
of the Director, and focus on master Layer objects. Also, keep in mind
that the generated code in the template is only trying to give you a
canvas as quickly as possible. It's not necessary the best starting
point for your project. It's up to you to make that decision.
Roger
What I am basically trying to do is to create one instance of a QGLWidget (or rather a derived class of QGLWidget), add it to a QMainWindow, and then access the QGLWidget's rendering context from anywhere in my QTCreator program to be able to call naked OpenGL anywhere I chose to.
Things I have tried:
1) Creating a subclass of QGLWidget called OGLWidget and making that into a singleton, and then trying to subclass the singleton class "OGLWidget". I thought this would give me access to the same rendering context that the OGLWidget singleton was using but it didn't work.
2) using the constructor QGLWidget(QWidget * parent, QGLWidget * shared, Qt::WindowFlags). For this one I tried casting the singleton object to a QGLWidget and then sticking it in this constructor when I was subclassing QGLWidget in another class called "Display". I tried calling makeCurrent before each classes openGl calls but only the original singleton would draw. I also checked isSharing and that returned true.
First of all, although signals\slots are a powerful and awesome feature of Qt I would never use them in my rendering routines because of the added overhead and render order problems; especially the latter. Besides, it's not necessary to do it the way you propose.
Thus, your idea of scattering the rendering routines all over your project is a very bad idea in my opinion.
What I do in my own project is the following:
My derived QGLWidget owns a Renderer class that's implemented as a Singleton. It contains all of the OpenGl calls in a few functions. I've created a system where everything that's drawable derives from the same base class. When I want to render, I build a render queue which I implemented as a priority_queue with custom sort function. When It's time for rendering a frame I just keep poppin' and rendering until the queue is empty.
Doing this with an event driven render system, while maintaining correct render order would probably drive you insane.
For completeness, my (simplified) QGLWidget definition:
#include <QtOpenGL/QGLWidget>
#include "global.h"
#include "renderer.h"
/**
* Derivation of QGLWidget.
*/
class Engine : public QGLWidget
{
Q_OBJECT
private:
Renderer* renderer;
private slots:
void renderTimeout(); // my render-loop is timer based
void onTap(QMouseEvent* qme);
void onMove(QMouseEvent* qme);
protected:
void initializeGL();
void resizeGL(int w, int h);
/* for debugging I use QPainter for drawing overlays,
* so I can't use PaintGL */
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent* qme);
void mouseMoveEvent(QMouseEvent* qme);
public:
Engine( QWidget* parent = 0 );
~Engine();
signals:
void tapOccurred(QMouseEvent* qme);
void moveOccurred(QMouseEvent* qme);
};
Why don't you just use what Qt has been designed for: use signals and slots? Maybe your problem is more complicated than what I get from it at first glance, but it seems to me that if you add slots to your QGLWidget and connect them to signals anywhere in your application, you accomplish exactly what you want. Connecting them can for example be done in the QMainWindow. This slot can then make a call to an implementation of paintGL() or paintEvent() to update the area in QGLWidget. Like this:
class MyQGLWidget : public QGLWidget {
// constructors and destructor...
protected:
void paintGL(); // <-- implement this in any way you want if you use OpenGL
void paintEvent(); // <-- or implement this one if you prefer using QPainter
public slots:
void updateMyWindow();
}
void MyQGLWidget::updateMyWindow() {
// Change some data here in any way you like
// ...
paintGL();
}