尝试使用SDL_WINDOWID在QT4中创建SDL小部件,但无法显示小部件

时间:2009-09-24 04:46:59

标签: c++ linux qt4 sdl

我正在尝试在简单的QT4窗口内创建SDL绘图画布,遵循提供的信息in the SDL wiki以及此站点上的另一个问题。该项目是使用QT和SDL的NES模拟器,我和朋友决定尝试创建。

目前,我有一个main_window类,它将包含我设置的SDL小部件,菜单,以及项目开发时可能包含的其他内容。我正在创建的SDL小部件称为rom_canvas,并从QWidget继承。到目前为止,我能够设置SDL_WINDOWID环境变量,我似乎能够与窗口小部件进行交互,因为我可以设置并获取其几何体并看到它实际上是“可见的”,但实际上并没有显示出来窗口。

到目前为止,我对QT4和SDL没有任何经验,并且没有大量的C ++经验,所以我可能会遗漏一些明显的东西。

这是rom_canvas类:

#include "rom_canvas.hpp"
#include <iostream>
#include <cstdlib>
#include <QString>

rom_canvas::rom_canvas(QWidget *parent)
 : QWidget(parent)
{
 parent->setAttribute(Qt::WA_PaintOnScreen);
 parent->setAttribute(Qt::WA_OpaquePaintEvent);
// setAttribute(Qt::WA_PaintOnScreen);
// setAttribute(Qt::WA_OpaquePaintEvent);

 setUpdatesEnabled(false);

 // a hack I found online to get the SDL surface to appear in our own window
 QString id;
 id.setNum(parent->winId());
    setenv("SDL_WINDOWID", id.toAscii().data(), 1);
 SDL_InitSubSystem(SDL_INIT_VIDEO);

 resize(320, 240);

 // change constants later
 sdl_screen = SDL_SetVideoMode(320, 240, DEFAULT_BPP, SDL_SWSURFACE);

 if(!sdl_screen)
  std::cout << "couldn't create screen" << std::endl;

 SDL_LockSurface(sdl_screen);
 SDL_FillRect(sdl_screen, NULL, 0x00FF0000);
 SDL_UnlockSurface(sdl_screen);
 SDL_UpdateRect(sdl_screen, 0, 0, 0, 0);
}

rom_canvas::~rom_canvas()
{
 // do NOT release sdl_screen here; that's done when SDL_Quit() is called in main().
}

// this method is a protected slot
void rom_canvas::test()
{
 std::cout << "rom_canvas test" << std::endl;
 SDL_LockSurface(sdl_screen);
 SDL_FillRect(sdl_screen, NULL, 0x00FF0000);
 SDL_UnlockSurface(sdl_screen);
 SDL_UpdateRect(sdl_screen, 0, 0, 0, 0);
}

这是main_window构造函数:

main_window::main_window(QWidget *parent)
 : QMainWindow(parent)
{
 canvas = new rom_canvas(this);
 setCentralWidget(canvas);
 canvas->setGeometry(100, 100, 100, 100);
 canvas->show();
 canvas->update();

 // Add File Menu
 open_action = new QAction(tr("&Open..."), this);
 open_action->setShortcuts(QKeySequence::Open);
 open_action->setStatusTip(tr("Open a new ROM"));
 connect(open_action, SIGNAL(triggered()), this, SLOT(select_rom()));

 exit_action = new QAction(tr("E&xit"), this);
 exit_action->setStatusTip(tr("Exit nesT"));
 connect(exit_action, SIGNAL(triggered()), /*QApplication::instance()*/canvas, SLOT(/*quit()*/test()));
 // Remember to change this back!!

 file_menu = menuBar()->addMenu(tr("&File"));
 file_menu->addAction(open_action);
 file_menu->addAction(exit_action);

 rom_dir = QDir::homePath();
}

代码有点凌乱,因为我一直在尝试让它发挥作用。任何帮助当然非常感谢。

2 个答案:

答案 0 :(得分:0)

所以我认为我至少可以展示一些东西。在稍微玩了一下代码之后,我最终评论了文件顶部的setAttribute方法,它似乎正在运行。此外,setUpdatesEnabled方法似乎没有影响,所以我删除了,因为我只是在那里试图让它工作。

下面是它的实际情况。我还没有代码刷新表面,所以我必须选择一个菜单选项来绘制它。看起来菜单栏正在关闭表面顶部,所以我将不得不弄清楚如何重新定位它。

希望这有助于某人。

SDL canvas http://img18.imageshack.us/img18/3453/nestsdl.png

答案 1 :(得分:0)

我猜你已经知道了,但是SDL_WINDOWID技巧可能不可移植 - 我很确定它在Mac上不起作用。我很好奇你想要SDL,在这种情况下 - 如果你只想要一个像素可寻址的图像缓冲区(或几个),使用QPixmap / QImage并坚持使用纯Qt。或者如果你想要SDL精灵功能,我建议将SDL复合到连接到QImage的内存缓冲区,然后将其绘制到Qt小部件。 (或者使用QImages作为精灵,并使用OpenGL QPainter后端)

在内部,Qt非常难以使用平台本机代码进行图像格式转换,因此即使这听起来相当复杂,我认为它足够快,并且比SDL_WINDOWID技巧更加强大和可移植。