Good morning,
This used to be a question, but it turns out I solved everything : the forum already has clues about how to do this, but no piece of code doing everything for you !
So this is what I’m delivering to you : the simplest way to include Panda in Qt, with everything handled (as far as I know).
It works with X11 and Windows too (thanks to Tah for Windows compatibility) !
It is composed of two classes :
-
QPandaApplication : reimplementing QApplication and including PandaFramework.
Note: you will need to explicitly terminate your application using the slot method “Close()”.
To get the instance of PandaFramework, use the static method Framework. -
QPandaWidget : a QWidget displaying a Panda3D window.
Note: everything is handled transparently by the widget. All you would need to draw is the WindowFramework embedded in the widget. You can get it with the method “Window()”.
You can’t use the WindowFramework before the widget has been initialized : wait for the Initialized signal to know when you can start drawing meshes all over the place.
This QWidget also supports the mousepress and mouserelease events : you can handle them like in any other QWidget by reimplementing mousePressEvent / mouseReleaseEvent. All the details of the click (except keyboard modifiers) are specified in the QMouseEvent.
qpandaapplication.h
#ifndef QPANDAAPPLICATION_H
# define QPANDAAPPLICATION_H
# include <QApplication>
# include <panda3d/pandaFramework.h>
# include <panda3d/pandaSystem.h>
class QPandaApplication : public QApplication
{
Q_OBJECT
public:
QPandaApplication(int argc, char **argv);
~QPandaApplication();
int exec(void);
static PandaFramework& Framework(void) { return (_framework); }
static void Close(void);
public slots:
void Terminate(void) { Close(); }
private:
static bool _continue;
static PandaFramework _framework;
};
#endif // QPANDAAPPLICATION_H
qpandaapplication.cpp
#include "qpandaapplication.h"
PandaFramework QPandaApplication::_framework;
bool QPandaApplication::_continue;
QPandaApplication::QPandaApplication(int argc, char **argv) : QApplication(argc, argv)
{
_framework.open_framework(argc, argv);
_continue = true;
}
QPandaApplication::~QPandaApplication()
{
_framework.close_framework();
}
int QPandaApplication::exec(void)
{
Thread* currentThread = Thread::get_current_thread();
do
{
processEvents();
} while (_continue && _framework.do_frame(currentThread));
return (0);
}
void QPandaApplication::Close(void)
{
_continue = false;
}
qpandawidget.hpp
#ifndef QPANDAWIDGET_H
# define QPANDAWIDGET_H
# include <QWidget>
# include <panda3d/pandaFramework.h>
# include <panda3d/pandaSystem.h>
class QPandaWidget : public QWidget
{
Q_OBJECT
public:
explicit QPandaWidget(QWidget *parent = 0);
virtual ~QPandaWidget();
virtual void resizeEvent(QResizeEvent*);
virtual void showEvent(QShowEvent*);
QPaintEngine* paintEngine() const { return (0); }
void paintEvent(QPaintEvent*) {}
virtual void closeEvent(QCloseEvent*);
WindowFramework* Window(void) const { return (_window); }
signals:
void Initialized(void);
private:
void UpdateSize(void);
static void CallbackMouse(const Event* event, void* ptr);
WindowFramework* _window;
QSize _size;
};
#endif // QPANDAWIDGET_H
qpandawidget.cpp
#include "qpandawidget.h"
#include <QResizeEvent>
#ifdef Q_WS_X11
# include <Qt/qx11info_x11.h>
# include <X11/Xlib.h>
#endif
#include <iostream>
#include "qpandaapplication.h"
QPandaWidget::QPandaWidget(QWidget *parent) : QWidget(parent)
{
EventHandler& events = QPandaApplication::Framework().get_event_handler();
_window = 0;
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_OpaquePaintEvent);
setFocusPolicy(Qt::StrongFocus);
events.add_hook("mouse1", QPandaWidget::CallbackMouse, this);
events.add_hook("mouse2", QPandaWidget::CallbackMouse, this);
events.add_hook("mouse3", QPandaWidget::CallbackMouse, this);
events.add_hook("mouse1-up", QPandaWidget::CallbackMouse, this);
events.add_hook("mouse2-up", QPandaWidget::CallbackMouse, this);
events.add_hook("mouse3-up", QPandaWidget::CallbackMouse, this);
}
QPandaWidget::~QPandaWidget()
{
EventHandler& events = QPandaApplication::Framework().get_event_handler();
events.remove_hooks_with(this);
if (_window)
QPandaApplication::Framework().close_window(_window);
}
void QPandaWidget::UpdateSize(void)
{
if (_window)
{
WindowProperties wp;
_window->get_graphics_window()->request_properties(wp);
wp.set_size(_size.width(), _size.height());
wp.set_origin(0, 0);
_window->get_graphics_window()->set_properties_now(wp);
}
}
void QPandaWidget::resizeEvent(QResizeEvent* event)
{
_size = event->size();
UpdateSize();
QWidget::resizeEvent(event);
}
void QPandaWidget::showEvent(QShowEvent* event)
{
if (_window == 0)
{
WindowProperties wp;
#ifdef Q_WS_X11
XFlush(QX11Info::display());
#endif
QPandaApplication::Framework().get_default_window_props(wp);
wp.set_parent_window((size_t)this->winId());
_window = QPandaApplication::Framework().open_window(wp, 0);
UpdateSize();
Initialized();
}
QWidget::showEvent(event);
}
void QPandaWidget::closeEvent(QCloseEvent*)
{
QPandaApplication::Close();
}
// MOUSE MANAGEMENT
void QPandaWidget::CallbackMouse(const Event* event, void* ptr)
{
QPandaWidget* instance = reinterpret_cast<QPandaWidget*>(ptr);
MouseData data = instance->_window->get_graphics_window()->get_pointer(0);
if (data.get_in_window())
{
QPoint pos(data.get_x(), data.get_y());
std::string name = event->get_name();
Qt::MouseButton button;
QMouseEvent::Type type;
char buttonN;
if (name.substr(name.size() - 2) == "up")
{
type = QMouseEvent::MouseButtonRelease;
name = name.substr(0, name.size() - 3);
}
else
type = QMouseEvent::MouseButtonPress;
buttonN = name[name.size() - 1];
name = name.substr(0, name.size() - 1);
switch (buttonN)
{
default:
case '1':
button = Qt::LeftButton;
break ;
case '2':
button = Qt::RightButton;
break ;
case '3':
button = Qt::MiddleButton;
break ;
}
if (type == QMouseEvent::MouseButtonPress)
{
QMouseEvent event(type, pos, button, 0, Qt::NoModifier);
instance->mousePressEvent(&event);
}
else
{
QMouseEvent event(type, pos, button, 0, Qt::NoModifier);
instance->mouseReleaseEvent(&event);
}
}
}
Here you go folks ! I really hope this will help !