1、方式一:
#include "mainwindow.h"
#include
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w_ui;
QGraphicsScene *scene = new QGraphicsScene;
QGraphicsProxyWidget *w = scene->addWidget(&w_ui);
w->setRotation(90);
QGraphicsView *view = new QGraphicsView(scene);
view->show();
return a.exec();
}
2、方式二:针对 linuxfb
(1) 修改linuxfb/qlinuxfbscreen.h,如下所示:
class QLinuxFbScreen : public QFbScreen
{
Q_OBJECT
public:
QLinuxFbScreen(const QStringList &args);
~QLinuxFbScreen();
bool initialize();
QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
QRegion doRedraw() Q_DECL_OVERRIDE;
private:
QStringList mArgs;
int mFbFd;
int mTtyFd;
// add by immortal start
int mRotation;
// add by immortal end
QImage mFbScreenImage;
int mBytesPerLine;
int mOldTtyMode;
struct {
uchar *data;
int offset, size;
} mMmap;
QPainter *mBlitter;
};
(2) 修改linuxfb/qlinuxfbscreen.cpp,如下所示:
QLinuxFbScreen::QLinuxFbScreen(const QStringList &args)
// : mArgs(args), mFbFd(-1), mTtyFd(-1), mBlitter(0) // modify by immortal
: mArgs(args), mFbFd(-1), mTtyFd(-1), mBlitter(0),mRotation(0)
{
mMmap.data = 0;
}
QLinuxFbScreen::~QLinuxFbScreen()
{
if (mFbFd != -1) {
if (mMmap.data)
munmap(mMmap.data - mMmap.offset, mMmap.size);
close(mFbFd);
}
if (mTtyFd != -1)
resetTty(mTtyFd, mOldTtyMode);
delete mBlitter;
}
bool QLinuxFbScreen::initialize()
{
QRegularExpression ttyRx(QLatin1String("tty=(.*)"));
QRegularExpression fbRx(QLatin1String("fb=(.*)"));
QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));
QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));
// add by immorta start
QRegularExpression rotationRx(QLatin1String("rotation=(0|90|180|270)"))
// add by immorta end
QString fbDevice, ttyDevice;
QSize userMmSize;
QRect userGeometry;
bool doSwitchToGraphicsMode = true;
// Parse arguments
foreach (const QString &arg, mArgs) {
QRegularExpressionMatch match;
if (arg == QLatin1String("nographicsmodeswitch"))
doSwitchToGraphicsMode = false;
else if (arg.contains(mmSizeRx, &match))
userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());
else if (arg.contains(sizeRx, &match))
userGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt()));
else if (arg.contains(offsetRx, &match))
userGeometry.setTopLeft(QPoint(match.captured(1).toInt(), match.captured(2).toInt()));
else if (arg.contains(ttyRx, &match))
ttyDevice = match.captured(1);
else if (arg.contains(fbRx, &match))
fbDevice = match.captured(1);
// add by immortal start
else if (arg.contains(rotationRx, &match))
mRotation = match.captured(1).toInt();
// add by immortal end
}
if (fbDevice.isEmpty()) {
fbDevice = QLatin1String("/dev/fb0");
if (!QFile::exists(fbDevice))
fbDevice = QLatin1String("/dev/graphics/fb0");
if (!QFile::exists(fbDevice)) {
qWarning("Unable to figure out framebuffer device. Specify it manually.");
return false;
}
}
// Open the device
mFbFd = openFramebufferDevice(fbDevice);
if (mFbFd == -1) {
qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice));
return false;
}
// Read the fixed and variable screen information
fb_fix_screeninfo finfo;
fb_var_screeninfo vinfo;
memset(&vinfo, 0, sizeof(vinfo));
memset(&finfo, 0, sizeof(finfo));
if (ioctl(mFbFd, FBIOGET_FSCREENINFO, &finfo) != 0) {
qErrnoWarning(errno, "Error reading fixed information");
return false;
}
if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) {
qErrnoWarning(errno, "Error reading variable information");
return false;
}
mDepth = determineDepth(vinfo);
mBytesPerLine = finfo.line_length;
QRect geometry = determineGeometry(vinfo, userGeometry);
// add by immortal start
QRect originalGeometry = geometry;
if( 90 == mRotation || 270 == mRotation )
{
int tmp = geometry.width();
geometry.setWidth(geometry.height());
geometry.setHeight(tmp);
}
// add by immortal end
mGeometry = QRect(QPoint(0, 0), geometry.size());
mFormat = determineFormat(vinfo, mDepth);
// modify by immortal start
// mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, geometry.size());
mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, originalGeometry.size());
// modify by immortal end
// mmap the framebuffer
mMmap.size = finfo.smem_len;
uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);
if ((long)data == -1) {
qErrnoWarning(errno, "Failed to mmap framebuffer");
return false;
}
// modify by immortal start
// mMmap.offset = geometry.y() * mBytesPerLine + geometry.x() * mDepth / 8;
mMmap.offset = originalGeometry.y() * mBytesPerLine + originalGeometry.x() * mDepth / 8;
// modify by immortal end
mMmap.data = data + mMmap.offset;
QFbScreen::initializeCompositor();
// modify by immortal start
// mFbScreenImage = QImage(mMmap.data, geometry.width(), geometry.height(), mBytesPerLine, mFormat);
mFbScreenImage = QImage(mMmap.data, originalGeometry.width(), originalGeometry.height(), mBytesPerLine, mFormat);
// modify by immortal end
mCursor = new QFbCursor(this);
mTtyFd = openTtyDevice(ttyDevice);
if (mTtyFd == -1)
qErrnoWarning(errno, "Failed to open tty");
switchToGraphicsMode(mTtyFd, doSwitchToGraphicsMode, &mOldTtyMode);
blankScreen(mFbFd, false);
return true;
}
QRegion QLinuxFbScreen::doRedraw()
{
QRegion touched = QFbScreen::doRedraw();
if (touched.isEmpty())
return touched;
if (!mBlitter)
mBlitter = new QPainter(&mFbScreenImage);
const QVector rects = touched.rects();
mBlitter->setCompositionMode(QPainter::CompositionMode_Source);
for (int i = 0; i < rects.size(); ++i)
// add by immortal start
{
if( 90 == mRotation || 270 == mRotation )
{
mBlitter->translate(mGeometry.height()/2, mGeometry.width()/2);
}
else if( 180 == mRotation )
{
mBlitter->translate(mGeometry.width()/2, mGeometry.height()/2);
}
if( mRotation != 0 )
{
mBlitter->rotate(mRotation);
mBlitter->translate(-mGeometry.width()/2, -mGeometry.height()/2);
}
// add by immortal end
mBlitter->drawImage(rects[i], *mScreenImage, rects[i]);
// add by immortal start
mBlitter->resetTransform();
// add by immortal end
}
return touched;
}
// grabWindow() grabs "from the screen" not from the backingstores.
// In linuxfb's case it will also include the mouse cursor.
QPixmap QLinuxFbScreen::grabWindow(WId wid, int x, int y, int width, int height) const
{
if (!wid) {
if (width < 0)
width = mFbScreenImage.width() - x;
if (height < 0)
height = mFbScreenImage.height() - y;
return QPixmap::fromImage(mFbScreenImage).copy(x, y, width, height);
}
QFbWindow *window = windowForId(wid);
if (window) {
const QRect geom = window->geometry();
if (width < 0)
width = geom.width() - x;
if (height < 0)
height = geom.height() - y;
QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height));
rect &= window->geometry();
return QPixmap::fromImage(mFbScreenImage).copy(rect);
}
return QPixmap();
}
2,配置环境变量:
export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0
注:方式二完全参考:linuxfb旋转
方式二旋转之后屏幕原点好像有点问题,不过这个可以通过QT程序去解决。具体解决的原理,我还没有看懂。
非常感谢immortal018。复制过来只是做个备份。
以上两种方式,都测试过,可行。