多屏顯示的原理其實很好理解,就拿橫向擴展來說:
計算機把桌面的 寬度擴展成了 w1(屏幕1的寬度) + w2(屏幕2的寬度) 。
當一個窗口的起始橫坐標 > w1,則 他就被顯示在第二個屏幕上了。
drm設備可以多用戶同時打開,FB獲取的用戶態虛擬內存地址映射到內核態物理內存地址也是不同的
多屏虛擬成一個桌面,QScreen Class。qtbase/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
QT可用的平臺插件有:xcb、eglfs、linuxfb、minimal、minimalegl、offscreen、vnc、wayland-egl、wayland、wayland-xcomposite-egl、wayland-xcomposite-glx、webgl等
?
qt的說明文檔中用一張圖闡述了這個情況:
?
QApplication 提供了一個獲得virtual desktop的方法:
QDesktopWidget *desktop = QApplication::desktop();
返回的 QDesktopWidget 存儲著當前桌面的信息。
注意 ,這個函數必須在創建了 QApplication 對象之后才能使用, 否則會出錯。具體原因,要問qt。
這個desktop有幾個很有用的函數,用來獲取當前的屏幕狀態和分辨率
1) int desktop->primaryScreen()
獲取主屏幕的索引序號,(windows開始菜單所在的屏幕為主屏幕), 每個副屏幕序號+1
2) int desktop->screenCount()
獲取當前屏幕個數
3) QRect desktop->screenGeometry(int screen_index)
根據當前的屏幕序號獲取屏幕寬高等屬性
4) int desktop->width()
獲取虛擬屏幕全寬, 注意這個比較猛,是獲取的總寬度,對于橫向擴展屏來說,也就是 屏幕1+ 屏幕2 + … 的寬度
5) int desktop->height()
獲取虛擬屏幕全高
下面的這個程序就可以測試多屏(只測了橫屏,沒測試縱屏): 根據當前屏幕數量n,生成n個窗口,每個窗口都占據了一個屏幕
#include "mainwindow.h"
#include <QApplication>
#include <QDesktopWidget>
#include <cstdio>
#include <QMessageBox>typedef struct{
int screen_no;
QRect rect;
}SCREEN;
SCREEN g_screens[10];int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QDesktopWidget *desktop = QApplication::desktop();int screen_count = desktop->screenCount();int prim_screen = desktop->primaryScreen();
char warning[100], *idx=warning;
for(int i=0; i<screen_count ;i++ ){
g_screens[i].screen_no = prim_screen + i;
g_screens[i].rect = desktop->screenGeometry(prim_screen + i);
sprintf(idx, "screen%d w[%d], h[%d] ",i, g_screens[i].rect.width(),g_screens[i].rect.height() );
idx += strlen(idx);
}
sprintf(idx, "total width[%d] , total height[%d] n", desktop->width(), desktop->height() );
QMessageBox::warning(NULL, "screen", warning, QMessageBox::Ok);MainWindow wnd[5];
for(int i=0; i < screen_count; i++){
wnd[i].resize(g_screens[i].rect.width(),g_screens[i].rect.height());
if(i == 0)
wnd[i].move(0,0);
else
wnd[i].move(i* g_screens[i-1].rect.width(),0);
char str[50];
sprintf(str,"this is screen %d",i);
wnd[i].show();
}
return app.exec();
}
想實現這樣一種功能:主程序的主窗口在PC上顯示,而其子dialog在另外的顯示器上顯示(做實驗時方便監控且不會有多余的干擾)。
方法如下 :建立Qdesktopwidget對象
QDesktopWidget* desktop = Application::desktop();
獲取當前顯示器的個數
N = desktop->screenCount();
如果有兩個顯示,則N=2,qt默認的計算機主機的index = 0,外接顯示器的index = 1;
QDialog 有個成員函數叫setGeometry,只需要將dialog對象的Geometry設置為index為1的顯示器即可,默認為0.如果要顯示的dialog的對象為mdlg,則
mdlg.setGeometry(desktop->screenGeometry(1));
mdlg.show();
#include <QDesktopWidget>//獲取屏幕信息
QDesktopWidget* desktop = QApplication::desktop(); //獲取屏幕對象(這個函數必須在創建了 QApplication 對象之后才能使用, 否則會出錯)
int screenNum = desktop->screenCount(); //獲取屏幕個數
int mainScreenID = desktop->primaryScreen(); //獲取主屏幕索引,(windows開始菜單所在的屏幕為主屏幕),每個副屏幕序號+1
QRect screenRect = desktop->screenGeometry(int screen_index); //根據屏幕索引獲取屏幕寬高等屬性
int screenWidth = desktop->width(); //獲取屏幕的寬
int screenWidth = desktop->height(); //獲取屏幕的高
for(int i=0; i<screenNum; ++i) { //獲取每塊屏幕分辨率 qDebug()<<"屏幕"<<i+1<<"分辨率: "<<desktop->screenGeometry(i).size();
} //======================================================================
//設置對話框mdlg顯示在副屏1的左上角坐標
QDialog mdlg;
mdlg.setGeometry(desktop->screenGeometry(1));
mdlg.show();
//======================================================================
//如果想全屏顯示在副屏1,則可以獲取副屏1的分辨率,更新對話框的大小再設置坐標
mdlg.resize(desktop->screenGeometry(1).size()); //設置對話框全屏
mdlg.setGeometry(desktop->screenGeometry(1)); //設置對話框對齊副屏1左上角坐標
mdlg.show();
//======================================================================
linuxfb實現多屏(QT5已廢棄)
如果多屏對應一個fb
那么應該可以知道不同屏對應fb顯示內存的位置,只要根據位置去畫窗口即可
如果多屏對應不同的設備 fb,可以運行下面的命令來指定不同的fb在qt顯示內存上的位置
./xxx -qws -display "Mutli:LinuxFb:0 LinuxFb:/dev/fb1:1:offset=0,1080"
xxx表示qt可執行文件
"Mutli:LinuxFb:0 LinuxFb:/dev/fb1:1:offset=0,1080"
表示有兩個輸出fb分別是 /dev/fb0, /dev/fb1,其中/dev/fb0的起始位置在 qt 顯示內存的(0,0), /dev/fb1的起始位置在 qt 顯示內存的(0,1080)
程序中(假設顯示分辨率為1920x1080)
在(0,0)到(1920,1080)范圍內畫窗口就顯示在fb0上,在(0,1080)到 (1920,2160)范圍畫窗口就顯示在fb1上
引申:內核態分配內存虛擬出一個fb0,操作fb0時,內核態程序將fb0內存復制到fb1和fb2內存中(前提是fb1和fb2的內核態地址即物理地址連續,且物理地址最好是固定的)。實際驗證?
利用Qt實現雙屏顯示
前提是設備中有兩個屏幕。這樣在linux中Qt實現雙屏顯示就很簡單了。只需要把窗口利用move函數移動到另一個屏幕的像素點就可以了。例如:一屏分辨率為:1280 * 800 ,二屏分辨率為:800 * 480。
(1)如果你定義了一個 1600 * 800的窗口,比一屏多出來400個像素點就會自動在二屏中顯示,不用任何處理(前提是你到設備雙屏能夠正常運行)
(2)如果想在一屏的基礎上點擊一個按鈕彈出一個窗口,而這個窗口想要在二屏上顯示,就需要利用move函數,把這個對話框的位置移動到二屏上顯示:move(1280,0);
對于上面的情況(1)(2),在linux上親測沒有問題,但是在ARM平臺上出現問題:在點擊了按鈕后,窗口并沒有在二屏上顯示,而是在一屏中顯示,而且置于最底層(原來的窗口擋住了這個窗口,因此并不能顯示出來)。
在ARM設備中正常雙屏顯示如下:
#ifdef DOUBLE_SCREENdesktop = QApplication::desktop();
int N = desktop->screenCount();
qDebug()<<"screen :"<<N;
qDebug()<<"screen1 rect:"<<desktop->screenGeometry(0);
qDebug()<<"screen2 rect:"<<desktop->screenGeometry(1);DoubleScreen *m_DoubleScreen = new DoubleScreen;
m_DoubleScreen->initLab(desktop->screenGeometry(1));
m_DoubleScreen->show();#endifvoid DoubleScreen::initLab(QRect rect)
{setGeometry(rect);this->resize(800,480);lab=new QLabel("this is desktop"+QString::number(num+1),this);lab->setGeometry(0,0,rect.width(),rect.height());lab->setAlignment(Qt::AlignCenter) ;}
上述代碼中DoubleScreen為繼承QMainWindow的類,而initLab為他到成員函數,將二屏的rect作為initLab的參數傳遞進來,然后通過setGeometry()函數就能將DoubleScreen的窗口顯示在二屏上了。