英文:
QPainter effects were removed when rendering a QOpenGLWidget into a QPixmap
问题
我有一个使用QPainter
进行OpenGL渲染和非OpenGL渲染的QOpenGLWidget
。小部件看起来正常,但当我尝试通过将其渲染到QPixmap
中来创建小部件的屏幕截图时,所有使用QPainter
绘制的效果突然消失了。以下是一个重现此问题的最小代码示例:
#include <QApplication>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QPushButton>
#include <QPainter>
class MainWidget : public QOpenGLWidget, QOpenGLFunctions {
public:
QPushButton* screenshot_button;
MainWidget(QWidget* parent=nullptr) : QOpenGLWidget(parent) {
screenshot_button = new QPushButton("截图", this);
QObject::connect(screenshot_button, &QPushButton::clicked, [this](){
take_screenshot();
});
}
void initializeGL() {
initializeOpenGLFunctions();
}
void take_screenshot() {
QPixmap pixmap(size());
render(&pixmap, QPoint(), QRegion(rect()));
pixmap.save("screenshot.png");
}
void paintGL() {
QPainter painter(this);
painter.beginNativePainting();
glClearColor(0.80, 0.80, 0.80, 1);
glClear(GL_COLOR_BUFFER_BIT);
painter.endNativePainting();
// 这在按下截图按钮时消失!
// 也不出现在截图中
painter.drawRect(QRect(0, 0, 100, 100));
}
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}
在按下按钮之前,小部件看起来正常:
但在按下截图按钮后,矩形从小部件中消失(在screenshot.png
中也不存在),直到我调整窗口大小以强制重新渲染。
我在Windows 10上使用Qt 6.5
。
英文:
I have a QOpenGLWidget
that does some OpenGL rendering and some non-OpenGL rendering using a QPainter
. The widget looks OK but when I try to create a screenshot of the widget by rendering it into a QPixmap
, suddenly all effects that are painted using QPainter
disappear. Here is a minimal code sample to reproduce the issue:
#include <QApplication>
#include <qopenglwidget.h>
#include <qopenglfunctions.h>
#include <qpushbutton.h>
#include <QPainter>
class MainWidget : public QOpenGLWidget, QOpenGLFunctions{
public:
QPushButton* screenshot_button;
MainWidget(QWidget* parent=nullptr) : QOpenGLWidget(parent){
screenshot_button = new QPushButton("sreenshot", this);
QObject::connect(screenshot_button, &QPushButton::clicked, [this](){
take_screenshot();
});
}
void initializeGL(){
initializeOpenGLFunctions();
}
void take_screenshot(){
QPixmap pixmap(size());
render(&pixmap, QPoint(), QRegion(rect()));
pixmap.save("screenshot.png");
}
void paintGL(){
QPainter painter(this);
painter.beginNativePainting();
glClearColor(0.80, 0.80, 0.80, 1);
glClear(GL_COLOR_BUFFER_BIT);
painter.endNativePainting();
// this disappears when the screenshot button is pressed!
// also it is not present in the screenshot
painter.drawRect(QRect(0, 0, 100, 100));
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}
Before pressing the button the widget looks normal:
But after pressing the screenshot button, the rectangle disappears from the widget (also it is absent from screenshot.png
) until I resize the window which forces a re-render.
I am using qt 6.5
on windows 10.
答案1
得分: 0
尝试这样做
#include <QApplication>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QPushButton>
#include <QPainter>
class MainWidget : public QOpenGLWidget, protected QOpenGLFunctions {
public:
QPushButton *screenshot_button;
MainWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {
screenshot_button = new QPushButton("截图", this);
QObject::connect(screenshot_button, &QPushButton::clicked, [this]() {
take_screenshot();
});
}
void initializeGL() {
initializeOpenGLFunctions();
}
void take_screenshot() {
QImage image = grabFramebuffer(); // 获取屏幕截图作为 QImage
QPixmap pixmap = QPixmap::fromImage(image); // 将 QImage 转换为 QPixmap
pixmap.save("screenshot.png");
}
void paintGL() {
QPainter painter(this);
painter.beginNativePainting();
glClearColor(0.80, 0.80, 0.80, 1);
glClear(GL_COLOR_BUFFER_BIT);
painter.endNativePainting();
painter.drawRect(QRect(0, 0, 100, 100));
}
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}
看起来你遇到了一个与在Qt应用程序中混合使用OpenGL渲染和基于QPainter的渲染相关的常见问题。问题源于绘图操作的执行顺序以及QPainter与OpenGL上下文之间的交互。要解决这个问题,你需要确保QPainter的渲染和OpenGL渲染得到正确同步。
你面临的问题是,当你使用render()
函数获取截图时,OpenGL渲染和基于QPainter的渲染没有得到同步。OpenGL渲染是在paintGL()
函数中执行的,而基于QPainter的渲染是在take_screenshot()
函数之后执行的。
为了解决这个问题,你应该确保使用QOpenGLWidget的grabFramebuffer()
函数来同步渲染。这个函数返回一个包含当前OpenGL帧缓冲内容的QImage,其中包括OpenGL和基于QPainter的渲染。
通过使用grabFramebuffer()
函数,你可以捕获当前OpenGL帧缓冲的状态,包括任何OpenGL渲染的内容以及基于QPainter的内容。这确保了两种类型的渲染都在截图中得到同步。
英文:
Try This
#include <QApplication>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QPushButton>
#include <QPainter>
class MainWidget : public QOpenGLWidget, protected QOpenGLFunctions {
public:
QPushButton *screenshot_button;
MainWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {
screenshot_button = new QPushButton("screenshot", this);
QObject::connect(screenshot_button, &QPushButton::clicked, [this]() {
take_screenshot();
});
}
void initializeGL() {
initializeOpenGLFunctions();
}
void take_screenshot() {
QImage image = grabFramebuffer(); // Get the screenshot as QImage
QPixmap pixmap = QPixmap::fromImage(image); // Convert QImage to QPixmap
pixmap.save("screenshot.png");
}
void paintGL() {
QPainter painter(this);
painter.beginNativePainting();
glClearColor(0.80, 0.80, 0.80, 1);
glClear(GL_COLOR_BUFFER_BIT);
painter.endNativePainting();
painter.drawRect(QRect(0, 0, 100, 100));
}
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}
It seems you're encountering a common issue related to mixing OpenGL rendering and QPainter-based rendering in a Qt application. The problem arises from the order in which the painting operations are performed and the interaction between QPainter and the OpenGL context. To address this issue, you need to ensure that the QPainter-based rendering and the OpenGL rendering are synchronized properly.
The problem you're facing is that when you take a screenshot using the render() function, the OpenGL rendering and the QPainter-based rendering are not synchronized. The OpenGL rendering is performed in the paintGL()
function, and the QPainter-based rendering is done afterward in the take_screenshot()
function.
To resolve this issue, you should make sure to synchronize the rendering by using the QOpenGLWidget's grabFramebuffer()
function. This function returns a QImage with the current OpenGL framebuffer
content, which includes both OpenGL and QPainter-based rendering.
I convert the QImage to a QPixmap before saving it.
By using the grabFramebuffer()
function, you capture the current state of the OpenGL framebuffer, including any OpenGL-rendered content as well as the QPainter-based content. This ensures that both types of rendering are synchronized and included in the screenshot.
答案2
得分: 0
Solution 1:
> grabWindow() 函数从屏幕上获取像素,而不是从窗口上获取,也就是说,如果有另一个窗口部分或完全覆盖了您要获取的窗口,您也会获取来自上层窗口的像素。
这意味着它从帧缓冲中获取,不像 QWidget::grab
和 QWidget::render
会要求小部件自行渲染。
因此,它可以用来替代 render()
,以避免与OpenGL结合使用时可能引起的问题:
void take_screenshot()
{
QGuiApplication::primaryScreen()->grabWindow(winId()).save("screenScreenshot.png");
}
Solution 2:
不太直接,但以防万一需要使用 render
。
在 take_screenshot()
中调用 render
时,使用一个 bool
来禁用OpenGL,并确保在调用之前调用 grabFramebuffer()
。
void take_screenshot()
{
grabFramebuffer();
QPixmap pixmap(size());
enable_opengl=false;
render(&pixmap, QPoint(), QRegion(rect()));
enable_opengl=true;
pixmap.save("renderScreenshot.png");
}
void paintGL()
{
QPainter painter(this);
if(enable_opengl)
{
glClearColor(0.80, 0.80, 0.80, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
painter.fillRect(QRect(10, 10, 100, 100), Qt::green);
}
英文:
Solution 1:
From QScreen::grabWindow()
documentation:
>The grabWindow() function grabs pixels from the screen, not from the window, i.e. if there is another window partially or entirely over the one you grab, you get pixels from the overlying window, too.
Meaning it grabs from the framebuffer unlike QWidget::grab
and QWidget::render
which ask the widget to render itself.
So it could be used instead of render()
to avoid the problems caused by combining the latter with OpenGL:
void take_screenshot()
{
QGuiApplication::primaryScreen()->grabWindow(winId()).save("screenScreenshot.png");
}
Solution 2:
Less straightforward but just in case render
is a must.
Use a bool
to disable openGL when calling render
in take_screenshot()
, and make sure you call grabFramebuffer()
before.
void take_screenshot()
{
grabFramebuffer();
QPixmap pixmap(size());
enable_opengl=false;
render(&pixmap, QPoint(), QRegion(rect()));
enable_opengl=true;
pixmap.save("renderScreenshot.png");
}
void paintGL()
{
QPainter painter(this);
if(enable_opengl)
{
glClearColor(0.80, 0.80, 0.80, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
painter.fillRect(QRect(10, 10, 100, 100), Qt::green);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论