¿Why is does not set the icon?
-
Hello, so im getting the icon from a .exe file but i dont see it in the QPushButton i just see a gray square, my logs says its set but it really dont.
Im using the extractIconFromExe function to extract the icon them im setting the icon like this button->setIcon(QIcon(pixmap));
#include "groups.h" #include "qdir.h" #include "ui_groups.h" #include "dbmanager.h" #include <QCursor> #include <QGridLayout> #include <QPushButton> #include <QMouseEvent> #include <QApplication> #include <QEvent> #include <QProcess> #include <windows.h> #include <QPixmap> #include <Windows.h> #include <QPainter> groups::groups(QWidget *parent, QString groupName) : QWidget(parent) , ui(new Ui::groups) ,m_groupName(groupName) { ui->setupUi(this); // Set the window to have a transparent background //setAttribute(Qt::WA_TranslucentBackground); // Remove window frame if desired (optional) setWindowFlags(Qt::FramelessWindowHint); // Set the window opacity to be semi-transparent (optional) // setWindowOpacity(0.9); setWindowFlags(windowFlags() | Qt::Popup); //this->setFocusPolicy(Qt::StrongFocus); // Make the window focusable // setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); // Optionally keep window always on top, if needed //this->setWindowState(Qt::WindowActive); // Set the window to stay on top of other windows // Install event filter to track mouse events globally QApplication::instance()->installEventFilter(this); // Get the current position of the mouse QPoint globalMousePos = QCursor::pos(); // Calculate the position to center the window's top at the mouse position int windowWidth = this->width(); int windowHeight = this->height(); // Define the margin (top space) you want between the cursor and the window int marginTop = 50; // Move the window so that its top-center is at the mouse position, plus the margin int xPos = globalMousePos.x() - windowWidth / 2; int yPos = globalMousePos.y() - windowHeight - marginTop; // Add margin to the vertical position move(xPos, yPos); // Set the window to stay on top of other windows //setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); // Create a central widget (if not already done in the .ui file) QWidget* centralWidget = new QWidget(this); //setCentralWidget(centralWidget); // Create a grid layout QGridLayout* layout = new QGridLayout; QString appDir = QCoreApplication::applicationDirPath(); QString dbPath = QDir(appDir).filePath("tgroups.db"); qDebug() << dbPath; DbManager *db = new DbManager(dbPath); QVector<DbManager::Group> groups; groups = db->getOneGroup(m_groupName); QVector<QString> groups_app_patch; for (int var = 0; var < groups.count(); ++var) { // Split the string by commas and add each element to the vector groups_app_patch = groups[var].data.split(","); // Split by comma // Trim spaces from each element (but keep quotes if present) for (int i = 0; i < groups_app_patch.size(); ++i) { // Trim only the spaces, leaving the quotes intact groups_app_patch[i] = groups_app_patch[i].trimmed(); } } // Create and add buttons to the layout int row = 0, col = 0; int maxCols = 4; // Maximum number of buttons in one row int buttonWidth = 40; int buttonHeight = 40; for (int i = 0; i < groups_app_patch.count(); ++i) { //qDebug() << groups_app_patch[i]; QFileInfo fileInfo(groups_app_patch[i]); QString fileName = fileInfo.fileName(); // Get the file name fileName.replace(".exe",""); // Get the last character of the file name QChar lastChar = fileName.right(1).at(0).toUpper(); QPushButton* button = new QPushButton( QString(fileName)[0].toUpper() + QString(lastChar)); qDebug() << "FILENAME " << lastChar; // Button Style button->setStyleSheet("QPushButton {" "background-color: transparent;" // Temporary background color for debugging "font: 900 9pt 'Arial Black';" "color: rgb(255, 255, 255);" "border: none;" "}" "QPushButton:hover {" "background-color: rgba(128, 128, 128, 0.5);" "color: rgb(255, 255, 255);" "border: none;}"); // Set button size button->setFixedSize(40, 40); // Extract icon from EXE QIcon icon = extractIconFromExe(groups_app_patch[i]); QPixmap pixmap = icon.pixmap(40, 40); // Resize to 40x40 for the button size // Check if the pixmap is valid if (!pixmap.isNull()) { QImage img = pixmap.toImage(); // Check if the image has transparency and if so, set a background color if (img.hasAlphaChannel()) { // Create a background image with the same size and fill it with a solid color QImage background(img.size(), QImage::Format_ARGB32); background.fill(Qt::lightGray); // Set a light gray background or any color // Composite the original icon over the background (keeping transparency in the icon) QPainter painter(&background); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); // Ensure proper blending mode painter.drawImage(0, 0, img); // Place the icon at position (0, 0) inside the background painter.end(); // Convert the modified image back to a pixmap pixmap = QPixmap::fromImage(background); } else { // If the icon doesn't have an alpha channel, simply place it on a background (optional) QImage background(img.size(), QImage::Format_ARGB32); background.fill(Qt::lightGray); // Fill with a background color if no transparency // Directly copy the icon onto the background QPainter painter(&background); painter.drawImage(0, 0, img); // Place the icon at position (0, 0) inside the background painter.end(); pixmap = QPixmap::fromImage(background); // Convert to pixmap again } button->setIcon(QIcon(pixmap)); // Set the pixmap with background button->setIconSize(QSize(40, 40)); // Set the icon size to match button size } else { qDebug() << "Icon is null, cannot set icon!"; } // Add button to layout layout->addWidget(button, row, col); layout->setSizeConstraint(QLayout::SetFixedSize); // Prevent layout from resizing // Connect the button to launch the application when clicked connect(button, &QPushButton::clicked, this, [i, groups_app_patch]() { QString appPath = groups_app_patch[i]; if (appPath.contains(" ")) { appPath = "\"" + appPath + "\""; // Wrap in quotes if path contains spaces } QProcess::startDetached(appPath); // Launch the .exe }); // Update layout position col++; if (col == maxCols) { col = 0; row++; } } // Set the layout to the central widget centralWidget->setLayout(layout); // Calculate window size based on button count and layout int totalButtons = groups_app_patch.count(); int totalRows = (totalButtons / maxCols) + (totalButtons % maxCols == 0 ? 0 : 1); // Calculate number of rows needed int width = buttonWidth * maxCols; // Width for 4 buttons in one row int height = totalRows * buttonHeight; // Height depends on the number of rows required // Set the minimum size of the window based on calculated width and height //setMinimumSize(width, height); resize(width + 30, height + 20); // Resize the window to the calculated size } groups::~groups() { delete ui; } QIcon groups::extractIconFromExe(const QString &exePath) { QFileInfo fileInfo(exePath); QString fileName = fileInfo.fileName(); // Get the file name qDebug() << "Extracting icon from file: " << fileName; HICON hIcon = ExtractIcon(NULL, exePath.toStdWString().c_str(), 0); if (hIcon == NULL) { qDebug() << "Failed to extract icon from" << exePath; return QIcon(); } else { qDebug() << "Successfully extracted icon from" << fileName; // Log the file name } // Convert HICON to QImage ICONINFO iconInfo; if (GetIconInfo(hIcon, &iconInfo)) { BITMAP bitmap; GetObject(iconInfo.hbmColor, sizeof(bitmap), &bitmap); HDC hdc = GetDC(NULL); HDC memDC = CreateCompatibleDC(hdc); HBITMAP hBitmap = (HBITMAP) SelectObject(memDC, iconInfo.hbmColor); BITMAPINFO bitmapInfo = {}; bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader); bitmapInfo.bmiHeader.biWidth = bitmap.bmWidth; bitmapInfo.bmiHeader.biHeight = -bitmap.bmHeight; // Negative to specify top-down bitmap bitmapInfo.bmiHeader.biPlanes = 1; bitmapInfo.bmiHeader.biBitCount = 32; int rowSize = ((bitmap.bmWidth * 32 + 31) / 32) * 4; QByteArray byteArray(rowSize * bitmap.bmHeight, 0); int bytesRead = GetDIBits(hdc, hBitmap, 0, bitmap.bmHeight, byteArray.data(), &bitmapInfo, DIB_RGB_COLORS); if (bytesRead == 0) { qDebug() << "Failed to retrieve icon bitmap data."; DestroyIcon(hIcon); return QIcon(); } QImage img(reinterpret_cast<const uchar *>(byteArray.data()), bitmap.bmWidth, bitmap.bmHeight, rowSize, QImage::Format_ARGB32); // Log the image dimensions to ensure the icon is extracted correctly qDebug() << "Extracted icon dimensions: " << img; SelectObject(memDC, hBitmap); DeleteDC(memDC); ReleaseDC(NULL, hdc); DestroyIcon(hIcon); return QIcon(QPixmap::fromImage(img)); // Convert to QIcon } DestroyIcon(hIcon); return QIcon(); }
-
Ok so this was the cause of the problem
incorrect handling of the bitmap data and improper configuration of the BITMAPINFO structure
Heres is the correct code.
QPixmap groups::extractPixmapFromExe(const QString &exePath) { QFileInfo fileInfo(exePath); QString fileName = fileInfo.fileName(); qDebug() << "Extracting icon from file: " << fileName; // Extract the icon from the executable HICON hIcon = ExtractIcon(NULL, exePath.toStdWString().c_str(), 0); if (hIcon == NULL) { qDebug() << "Failed to extract icon from" << exePath; return QPixmap(); // Return an empty pixmap if icon extraction fails } // Get icon information ICONINFO iconInfo; if (!GetIconInfo(hIcon, &iconInfo)) { qDebug() << "Failed to get icon info."; DestroyIcon(hIcon); return QPixmap(); } // Get the color bitmap information BITMAP bitmap; if (!GetObject(iconInfo.hbmColor, sizeof(bitmap), &bitmap)) { qDebug() << "Failed to get bitmap info."; DestroyIcon(hIcon); return QPixmap(); } // Create a device context for the bitmap HDC hdc = GetDC(NULL); HDC memDC = CreateCompatibleDC(hdc); HBITMAP hOldBitmap = (HBITMAP)SelectObject(memDC, iconInfo.hbmColor); // Prepare the BITMAPINFO structure BITMAPINFO bmi = {}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = bitmap.bmWidth; bmi.bmiHeader.biHeight = -bitmap.bmHeight; // Negative for top-down bitmap bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; // Allocate a buffer for the bitmap data QByteArray buffer(bitmap.bmWidth * bitmap.bmHeight * 4, 0); // 32-bit ARGB format // Retrieve the bitmap data if (!GetDIBits(memDC, iconInfo.hbmColor, 0, bitmap.bmHeight, buffer.data(), &bmi, DIB_RGB_COLORS)) { qDebug() << "Failed to retrieve bitmap data."; SelectObject(memDC, hOldBitmap); DeleteDC(memDC); ReleaseDC(NULL, hdc); DestroyIcon(hIcon); return QPixmap(); } // Create a QImage from the bitmap data QImage img(reinterpret_cast<const uchar*>(buffer.constData()), bitmap.bmWidth, bitmap.bmHeight, QImage::Format_ARGB32); // Clean up resources SelectObject(memDC, hOldBitmap); DeleteDC(memDC); ReleaseDC(NULL, hdc); DestroyIcon(hIcon); // Convert the QImage to a QPixmap and return it return QPixmap::fromImage(img); }
-
@illudharpyja said in ¿Why is does not set the icon?:
QImage img(reinterpret_cast<const uchar *>(byteArray.data()), bitmap.bmWidth, bitmap.bmHeight, rowSize, QImage::Format_ARGB32);
You should read the documentation to the functions you're using: https://doc.qt.io/qt-6/qimage.html#QImage-9
"The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. "
-
repository: https://github.com/illud/tgroup
Problem is in file: groups.cppI've tried several things still not get it to work, logs says is set and its even showing me the icon size but still not rendered on each button
How i call it
// Extract the icon directly into a QPixmap QPixmap pixmap = extractPixmapFromExe(groups_app_patch[i]); // Check if the pixmap is valid if (pixmap.isNull()) { qDebug() << "Failed to extract icon from:" << groups_app_patch[i]; } else { // Set the pixmap as the button's icon button->setIcon(QIcon(pixmap)); button->setIconSize(QSize(32, 32)); // Set the icon size to match the button qDebug() << "Icon extracted successfully for:" << groups_app_patch[i]; }
icon extraction
QPixmap groups::extractPixmapFromExe(const QString &exePath) { QFileInfo fileInfo(exePath); QString fileName = fileInfo.fileName(); qDebug() << "Extracting icon from file: " << fileName; HICON hIcon = ExtractIcon(NULL, exePath.toStdWString().c_str(), 0); if (hIcon == NULL) { qDebug() << "Failed to extract icon from" << exePath; return QPixmap(); // Return an empty pixmap if icon extraction fails } // Extract icon information ICONINFO iconInfo; if (GetIconInfo(hIcon, &iconInfo)) { BITMAP bitmap; GetObject(iconInfo.hbmColor, sizeof(bitmap), &bitmap); HDC hdc = GetDC(NULL); HDC memDC = CreateCompatibleDC(hdc); HBITMAP hBitmap = (HBITMAP)SelectObject(memDC, iconInfo.hbmColor); BITMAPINFO bitmapInfo = {}; bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader); bitmapInfo.bmiHeader.biWidth = bitmap.bmWidth; bitmapInfo.bmiHeader.biHeight = -bitmap.bmHeight; // Negative to specify top-down bitmap bitmapInfo.bmiHeader.biPlanes = 1; bitmapInfo.bmiHeader.biBitCount = 32; int rowSize = ((bitmap.bmWidth * 32 + 31) / 32) * 4; QByteArray byteArray(rowSize * bitmap.bmHeight, 0); int bytesRead = GetDIBits(hdc, hBitmap, 0, bitmap.bmHeight, byteArray.data(), &bitmapInfo, DIB_RGB_COLORS); if (bytesRead == 0) { qDebug() << "Failed to retrieve icon bitmap data."; DestroyIcon(hIcon); return QPixmap(); } // Create a QImage from the QByteArray buffer QImage img(reinterpret_cast<const uchar *>(byteArray.constData()), bitmap.bmWidth, bitmap.bmHeight, rowSize, QImage::Format_ARGB32); // Create and return a QPixmap from the QImage QPixmap pixmap = QPixmap::fromImage(img); DestroyIcon(hIcon); // Clean up the icon handle return pixmap; } DestroyIcon(hIcon); // Clean up the icon handle if it failed to get icon info return QPixmap(); }
¿Is there something im not aware of?
-
@illudharpyja said in ¿Why is does not set the icon?:
¿Is there something im not aware of?
I already told you the most possible reason...
-
Ok so this was the cause of the problem
incorrect handling of the bitmap data and improper configuration of the BITMAPINFO structure
Heres is the correct code.
QPixmap groups::extractPixmapFromExe(const QString &exePath) { QFileInfo fileInfo(exePath); QString fileName = fileInfo.fileName(); qDebug() << "Extracting icon from file: " << fileName; // Extract the icon from the executable HICON hIcon = ExtractIcon(NULL, exePath.toStdWString().c_str(), 0); if (hIcon == NULL) { qDebug() << "Failed to extract icon from" << exePath; return QPixmap(); // Return an empty pixmap if icon extraction fails } // Get icon information ICONINFO iconInfo; if (!GetIconInfo(hIcon, &iconInfo)) { qDebug() << "Failed to get icon info."; DestroyIcon(hIcon); return QPixmap(); } // Get the color bitmap information BITMAP bitmap; if (!GetObject(iconInfo.hbmColor, sizeof(bitmap), &bitmap)) { qDebug() << "Failed to get bitmap info."; DestroyIcon(hIcon); return QPixmap(); } // Create a device context for the bitmap HDC hdc = GetDC(NULL); HDC memDC = CreateCompatibleDC(hdc); HBITMAP hOldBitmap = (HBITMAP)SelectObject(memDC, iconInfo.hbmColor); // Prepare the BITMAPINFO structure BITMAPINFO bmi = {}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = bitmap.bmWidth; bmi.bmiHeader.biHeight = -bitmap.bmHeight; // Negative for top-down bitmap bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; // Allocate a buffer for the bitmap data QByteArray buffer(bitmap.bmWidth * bitmap.bmHeight * 4, 0); // 32-bit ARGB format // Retrieve the bitmap data if (!GetDIBits(memDC, iconInfo.hbmColor, 0, bitmap.bmHeight, buffer.data(), &bmi, DIB_RGB_COLORS)) { qDebug() << "Failed to retrieve bitmap data."; SelectObject(memDC, hOldBitmap); DeleteDC(memDC); ReleaseDC(NULL, hdc); DestroyIcon(hIcon); return QPixmap(); } // Create a QImage from the bitmap data QImage img(reinterpret_cast<const uchar*>(buffer.constData()), bitmap.bmWidth, bitmap.bmHeight, QImage::Format_ARGB32); // Clean up resources SelectObject(memDC, hOldBitmap); DeleteDC(memDC); ReleaseDC(NULL, hdc); DestroyIcon(hIcon); // Convert the QImage to a QPixmap and return it return QPixmap::fromImage(img); }
-