在Qt上使用SDL2绘制QWidget: https://www.kurukurumi.com/blog/?post=54
离线
在Qt上使用SDL2绘制QWidget: https://www.kurukurumi.com/blog/?post=54
通过SDL2的SDL_CreateWindowFrom函数将QWidget转换为SDL_Window。
SDL_Window *window = SDL_CreateWindowFrom((void*)this->winId())
Qt只能在QWidget的paintEvent事件里进行绘图。
virtual void QWidget::paintEvent(QPaintEvent* event);
源码如下:
/*
File : SDL2Widget.h
Author : hubenchang0515@outlook.com
Blog : www.kurukurumi.com
*/
#ifndef SDL2WIDGET_H
#define SDL2WIDGET_H
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <QWidget>
#include <QPaintEvent>
class SDL2Widget : public QWidget
{
Q_OBJECT
public:
SDL2Widget(QWidget* parent=0);
~SDL2Widget();
protected:
void paintEvent(QPaintEvent* event);
private:
SDL_Window *window;
SDL_Renderer *render;
SDL_Surface *surface;
SDL_Texture *texture;
};
#endif
SDL2Widget.cpp:
/*
File : SDL2Widget.cpp
Author : hubenchang0515@outlook.com
Blog : www.kurukurumi.com
*/
#include <SDL2Widget.h>
SDL2Widget::SDL2Widget(QWidget* parent):QWidget(parent)
{
/* SDL2初始化 */
SDL_Init(SDL_INIT_EVERYTHING);
/* 把QWidget转换为SDL_Window */
window = SDL_CreateWindowFrom((void*)this->winId());
/* SDL2 Image初始化 */
IMG_Init(IMG_INIT_PNG);
/* 加载图片,创建surface */
surface = IMG_Load("demo.jpg");
}
SDL2Widget::~SDL2Widget()
{
}
/* 绘图操作必须在paintEvent事件里进行 */
void SDL2Widget::paintEvent(QPaintEvent* event)
{
/* 在window上创建一个render */
render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED
| SDL_RENDERER_PRESENTVSYNC);
/* 创建一个texture */
texture = SDL_CreateTextureFromSurface(render, surface);
/* 清空render的内容 */
SDL_RenderClear(render);
/* 将texture复制到render上 */
SDL_RenderCopy(render, texture, NULL, NULL);
/* 将render显示到window上 */
SDL_RenderPresent(render);
SDL_RenderPresent(render); //我的电脑上,需要调用两次才能显示出来,原因不明
/* 销毁render和texture,释放内存 */
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(render);
}
main.cpp:
/*
File : main.cpp
Author : hubenchang0515@outlook.com
Blog : www.kurukurumi.com
*/
#include <QApplication>
#include <SDL2Widget.h>
#include <QLayout>
#include <QPushButton>
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
QVBoxLayout* layout = new QVBoxLayout;
SDL2Widget* sdlWidget = new SDL2Widget;
QPushButton* button = new QPushButton("Button");
layout->addWidget(sdlWidget);
layout->addWidget(button);
QWidget w;
w.setLayout(layout);
w.show();
w.resize(640,400);
QObject::connect(button,&QPushButton::clicked,
sdlWidget,(void(SDL2Widget::*)(void))&SDL2Widget::repaint);
return app.exec();
}
运行结果:
离线
几经折腾, 上面的代码跑是能跑, 但是图片要么不显示, 要么会闪, Ubuntu和Win7都测试过。
离线
先把代码备份上来吧, 免得等会自己都找不到了: SDL2Widget_2019111817.7z
windows VC 版本 SDL预编译库:
https://www.libsdl.org/projects/SDL_image/release/SDL2_image-devel-2.0.5-VC.zip
https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.5-win32-x86.zip
还有mingw 我没有下载:
离线
找到一个7年前 qt 调用 ffmpeg 解码到 sdl2 的demo: https://github.com/zackxue/videoPlayer/blob/master/qtsdl2.cpp
应该可以借鉴一下吧。
离线
http://qaru.site/questions/1199981/sdl2-rendering-into-qwidget
试了一下这个demo, 可以用
QWidget中的SDL2渲染
我正在寻找我在GTK2和SDL1.2,QT5和SDL2.0.3中编写的仿真器端口。到目前为止,这还不错,因为仿真器在SDL2中独立工作,而图形界面在QT中也可以正常工作,两者都可以交互。我的问题是尝试在QWidget中获取SDL2。这是在使用窗口黑客方法的SDL1.2中正常工作的方法。
从我在Internet上阅读的所有内容中,都可以使用从QT小部件SDL_CreateWindowFrom接收winId()并将其传递给它的函数来禁用此功能。但是,这类似于使用openGL时的情况。
我想知道当im仅使用标准SDL2绘图功能获取纹理而不使用OpenGL时如何执行此操作。到目前为止,我所有的尝试都失败了,并且SDL根本没有出现在小部件中。
另外,我知道您可以将SDL_Suface转换为QImage。每次更新QImage(每秒60帧)时,如何开始更新QT Widget。这样做的复杂性在于QT和SDL在单独的线程中工作。
如果有人对方向有所了解,请指出我或一些有用的代码示例,这些示例可以得出答案,我将不胜感激。我尚未提供代码,因为我不确定如何执行此操作以提供任何代码。
EDIT
因此,在使用SDL和QT进行了一些测试之后。我设法使用标准绘画工具获得了用于在QWidget中进行绘画的SDL2。但是,这仅在将渲染器设置为时有效SDL_RENDERER_SOFTWARE。如果我尝试使用SDL_RENDERER_ACCELERATED,我也会尝试。这导致以下事实:QT窗口被完全阻止,无法绘制任何内容(包括窗口中的所有其他小部件),并最终由于不响应操作系统而终止(在我的测试案例中为Kubuntu)。
是否有人对为什么会这样有任何想法。SDL_RENDERER_ACCELERATED当SDL2绘制到由SDL_CreateWindow和创建的窗口中时,我可以完美地使用它SDL_CreateRenderer。这是在QWidget上绘制时的唯一问题。
这是我仍然拥有的代码:
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <SDL2/SDL.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindowFrom((void*)w.ptr_gfx->winId());
SDL_Renderer* render = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
SDL_SetRenderDrawColor(render, 255, 0, 0, 255);
SDL_RenderFillRect(render, NULL);
SDL_RenderPresent(render);
return a.exec();
SDL_DestroyWindow(window);
SDL_DestroyRenderer(render);
SDL_Quit();
}
主窗口 mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ptr_gfx = ui->gfx;
ui->gfx->setUpdatesEnabled(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
主窗口 mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Ui::MainWindow *ui;
QWidget* ptr_gfx;
};
#endif // MAINWINDOW_H
界面文件 mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QWidget" name="gfx" native="true">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>191</width>
<height>131</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
离线
Qt 操作 SDL 生成色块,并显示到 QImage 控件。
离线
随机颜色和载入图片都可以了。
离线
Linux 小改了一下, 跑一跑 OK
离线