I'm trying to get a live view of a specific window using Qt6.6. So far I have succeed to do that for the whole screen. However, when I implemented the code for a specific window I get stuck at capturing the window screen as QPixmap. The object is QWindowCapture but it doesn't have a method for capturing or something similar. Once I get that, I'll convert it into OpenCV format for further processing which is what I have done with screen capturing. That's my goal why I need capturing.
Here is the code if you want to try it:
#include <QApplication>
#include <QScreen>
#include <QPixmap>
#include <QImage>
#include <opencv2/opencv.hpp>
#include <QAbstractListModel>
#include <QCapturableWindow>
#include <QWindowCapture>
QT_USE_NAMESPACE
class WindowListModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit WindowListModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QCapturableWindow window(const QModelIndex &index) const;
public Q_SLOTS:
void populate();
private:
QList<QCapturableWindow> windowList;
};
class Screenshot {
public:
void displayLiveView();
private:
QPixmap grabScreen();
};
QPixmap Screenshot::grabScreen() {
QScreen *screen = QGuiApplication::primaryScreen();
if (!screen)
return QPixmap();
return screen->grabWindow(0);
}
void Screenshot::displayLiveView() {
while (true) {
QPixmap pixmap = grabScreen();
if (pixmap.isNull()) {
qDebug() << "Failed to capture the screen.";
continue;
}
QImage image = pixmap.toImage();
cv::Mat mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
cv::imshow("Live View", mat);
// Break if 'ESC' is pressed
if (cv::waitKey(30) == 27) {
break;
}
}
}
void captureAndShowWindow(const QString& windowName) {
// Obtain a list of available windows
WindowListModel windowListModel;
windowListModel.populate();
QCapturableWindow targetWindow; // Window we are looking for
bool windowFound = false;
for (int i = 0; i < windowListModel.rowCount(); i++) {
QModelIndex index = windowListModel.index(i);
if (index.isValid()) {
QString currentWindowDesc = windowListModel.data(index, Qt::DisplayRole).toString();
if (currentWindowDesc.contains(windowName)) {
targetWindow = windowListModel.window(index);
windowFound = true;
break;
}
}
}
if (!windowFound) {
qDebug() << "Window not found!";
return;
}
// Capture the specific window
QWindowCapture windowCapture;
windowCapture.setWindow(targetWindow);
//STUCK
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// Print available windows
WindowListModel model;
for (int i = 0; i < model.rowCount(); i++) {
QModelIndex index = model.index(i);
if (index.isValid()) {
QString windowDesc = model.data(index, Qt::DisplayRole).toString();
std::cout << i + 1 << ". " << windowDesc.toStdString() << std::endl;
}
}
Screenshot screenshot;
screenshot.displayLiveView();
captureAndShowWindow("Settings");
return 0;
}
The CMakeLists:
cmake_minimum_required(VERSION 3.10)
project(ScreenshotApp)
# Set up the required version of Qt
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
include_directories(include)
list(APPEND CMAKE_PREFIX_PATH "/home/user/Qt/6.6.0/gcc_64/lib/cmake")
find_package(Qt6 COMPONENTS Widgets Multimedia REQUIRED)
find_package(OpenCV 4.7.0 REQUIRED)
set_property(SOURCE main.cpp PROPERTY SKIP_AUTOMOC ON)
add_executable(main main.cpp ${SOURCES})
target_link_libraries(main Qt6::Widgets ${OpenCV_LIBS} Qt6::Multimedia)
Now I'm working on Ubuntu but later the code should run on Windows.
The trick is to get
targetWindowIdand feed that toQScreen grabWindow. This will give youQPixmapformat which is easily converted intoOpenCVcv::Mat.For that I picked a class which is called private in Qt source code because it is not part of their API.