convert GIcon to QIcon - qt

Is there a way to convert between these datatypes? I'm working with Qt but still need some of glib capabilities and I haven't found a way to do this. I need to get a list of the installed applications with GAppInfo and show it in a QListView and to do so I need to get the icon for those applications. Extracting it using g_app_info_get_icon returns a GIcon and what I need to work with is a QIcon in order to get it's QVariant.

GIcon does not provide the actual pixmap for the icon.
You need to load an actual pixmap by requesting icon of certain size.
#include <gio/gdesktopappinfo.h>
#include <gtk/gtk.h>
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QIcon icon;
GAppInfo *appInfo = (GAppInfo *)g_desktop_app_info_new("vlc.desktop");
GIcon *gicon = g_app_info_get_icon(appInfo);
QList<int> sizes; sizes << 16 << 24 << 32 << 48 << 64;
foreach (int size, sizes) {
GtkIconInfo *iconInfo = gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_default(), gicon, size, (GtkIconLookupFlags)0);
GdkPixbuf *pixbuf = gtk_icon_info_load_icon(iconInfo, NULL);
if (pixbuf == NULL)
continue;
QImage image(
gdk_pixbuf_get_pixels(pixbuf),
gdk_pixbuf_get_width(pixbuf),
gdk_pixbuf_get_height(pixbuf),
gdk_pixbuf_get_rowstride(pixbuf),
QImage::Format_ARGB32);
g_object_unref(pixbuf);
image.save("icon-" + QString::number(size) + ".png");
icon.addPixmap(QPixmap::fromImage(image));
}
g_object_unref(gicon);
return 0;
}

Related

There is no Format_RGB24 in qt6

In QT5 we have QVideoFrame::Format_RGB24 format (i have RGB images without alpha channel).
In QT6 (6.2.0) this format is missing.
Why this format has been removed?
What's the best way to convert RGB -> RGBX (A) in QT6?
If you are using QImage (or you can convert it to QImage) then you can convert the format to QImage::Format_RGBX8888 and then copy the bits:
#include <QGuiApplication>
#include <QImage>
#include <QVideoFrame>
#include <QVideoFrameFormat>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QImage image(100, 100, QImage::Format_RGB888);
image.fill(QColor(50, 100, 200));
if(image.format() == QImage::Format_Invalid)
return EXIT_FAILURE;
QVideoFrameFormat video_frame_format(image.size(), QVideoFrameFormat::Format_RGBX8888);
QImage rgbx = image.convertToFormat(QVideoFrameFormat::imageFormatFromPixelFormat(video_frame_format.pixelFormat()));
QVideoFrame video_frame(video_frame_format);
if(!video_frame.isValid() || !video_frame.map(QVideoFrame::WriteOnly)){
qWarning() << "QVideoFrame is not valid or not writable";
return EXIT_FAILURE;
}
int plane = 0;
std::memcpy(video_frame.bits(plane), rgbx.bits(), video_frame.mappedBytes(plane));
video_frame.unmap();
qDebug() << video_frame << rgbx.format();
return EXIT_SUCCESS;
}

QListView max number of items in view

I need to calculate max number of items in current view of QListView.
I wrote code like this:
void MyListView::resizeEvent(QResizeEvent *event)
{
QListView::resizeEvent(event);
QFontMetrics fm (this->font());
int fontHeight = fm.lineSpacing();
QRect cr = contentsRect();
int windowHeight = cr.bottom() - cr.top();
int maxItemsCount = windowHeight / fontHeight;
qDebug()<<"max items in view: "<< maxItemsCount;
}
but calculated max number of items is is incorrect.
E.g. in case of my window height and font height I get 32 max items in view when in fact current view has 28 items. Perhaps someone can suggest something, how to calculate it properly?
My idea is to use QListView::indexAt() (inherited from QAbstractView) to obtain the row index for
the top-left corner
the bottom-left corner
of the list view viewport and determining the number of visible items by difference of them.
To check this out, I made an MCVE testQListViewNumVisibleItems.cc:
// Qt header:
#include <QtWidgets>
class ListWidget: public QListWidget {
public:
ListWidget(QWidget *pQParent = nullptr): QListWidget(pQParent) { }
virtual ~ListWidget() = default;
ListWidget(const ListWidget&) = delete;
ListWidget& operator=(const ListWidget&) = delete;
int getNumVisibleItems() const
{
const QSize size = viewport()->size();
const QModelIndex qMIdx0 = indexAt(QPoint(0, 0));
const QModelIndex qMIdx1 = indexAt(QPoint(0, size.height() - 1));
//qDebug() << "qMIdx0:" << qMIdx0 << "qMIdx1:" << qMIdx1;
return qMIdx0.isValid()
? (qMIdx1.isValid() ? qMIdx1.row() : count()) - qMIdx0.row()
: 0;
}
};
const int MaxItems = 20;
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
ListWidget qLst;
qLst.resize(200, 200);
qLst.show();
// timer to populate list view
using namespace std::chrono_literals;
QTimer qTimer;
qTimer.setInterval(1000ms);
// install signal handlers
int n = 0;
QObject::connect(&qTimer, &QTimer::timeout,
[&]() {
qLst.addItem(QString("item %0").arg(++n));
qDebug() << "Visible items:" << qLst.getNumVisibleItems();
if (n >= MaxItems) qTimer.stop();
});
// runtime loop
qTimer.start();
return app.exec();
}
and a CMakeLists.txt:
project(QListViewNumVisibleItems)
cmake_minimum_required(VERSION 3.10.0)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Qt5Widgets CONFIG REQUIRED)
include_directories("${CMAKE_SOURCE_DIR}")
add_executable(testQListViewNumVisibleItems testQListViewNumVisibleItems.cc)
target_link_libraries(testQListViewNumVisibleItems Qt5::Widgets)
built and tested in VS2017 on Windows 10:
After having implemented what came in my mind, I googled a bit to possibly see other approaches. (I admit I should've done before.)
Thereby I found the following possible duplicate:
SO: Simple way to get all visible items in the QListView
The accepted answer doesn't contain much more than the hint for indexAt and a link to a Qt-FAQ article:
How can i get hold of all of the visible items in my QListView?
In order to get hold of the visible items in a QListView http://doc.qt.io/qt-5/qlistview.html, then you can iterate over them using indexAt() http://doc.qt.io/qt-5/qlistview.html#indexAt. You can get hold of the first visible item using indexAt(QPoint(0, 0)), then in order to get the index at the next position then use visualRect() http://doc.qt.io/qt-5/qlistview.html#visualRect to find out what your next call to itemAt() should be. This position would be:
visualRect.y() + visualRect.height() + 1 effectively.
See the following example for an illustration:
#include <QtGui>
QList <QModelIndex>myList;
class ListView : public QListView
{
Q_OBJECT
public:
ListView()
{
QStringListModel *myModel = new QStringListModel(this);
QStringList list;
list << "a" << "b" <<"c" <<"d" <<"e" <<"f" <<"g" <<"h" <<"i" <<"j" <<"k";
myModel->setStringList(list);
setModel(myModel);
QTimer::singleShot(3000, this, SLOT(test1()));
}
public slots:
void test1()
{
QModelIndex firstIndex = indexAt(QPoint(0, 0));
if (firstIndex.isValid()) {
myList << firstIndex;
} while (viewport()->rect().contains(QPoint(0, visualRect(firstIndex).y() + visualRect(firstIndex).height() + 1 ))) {
firstIndex = indexAt(QPoint(0, visualRect(firstIndex).y() + visualRect(firstIndex).height() + 1 ));
myList << firstIndex;
}
qDebug() << myList.count() << "are visible";
}
};
#include "main.moc"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
ListView window;
window.resize(100, 50);
window.show();
return app.exec();
}

How to translate/crop a QImage with subpixel accuracy?

The use case is a 2D map with a vehicle at the origin. The map shall also be translated in case the vehicle moves e.g. 0.5 pixels. I believe this should be feasible using bilinear interpolation or similar.
If there is no simple solution using Qt, I would appreciate hints to non-Qt-solutions.
Minimal example:
#include <QtWidgets/QApplication>
#include <QtGui/QImage>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Parameters
QString PATH_IMG_IN = "../img_test_rect.jpg";
QString PATH_IMG_OUT = "../img_out.png";
float TRANSLATE_IN_PX = 0.5;
// load image
QImage img;
img.load(PATH_IMG_IN);
// rotate image.
QTransform trans;
trans.translate(0,TRANSLATE_IN_PX);
QImage img_new = img.transformed(trans, Qt::SmoothTransformation);
// save image
img_new.save(PATH_IMG_OUT, nullptr, 100);
// optional: Get info about true transformation matrix
QTransform trans_true = QImage::trueMatrix(trans, img.width(), img.height());
return app.exec();
}
Given an input image with a sharp border (see below), I would expect the output image to have a blurred border. This is not the case:
How to fix that?
I tested openCV and its function cv::warpAffine allows translation with sub-pixel precision (see MWE below).
After founding some old, unanswered threads on qtcentre.org, it seems to me that Qt simply does not allow translation with sub-pixel precision. Please correct me if I am wrong.
For Qt, I only found workarounds to scale the image first, translate with pixel accuracy and scale down again. Unfortunately, this approach is too computationally expensive for my use case.
MWE with opencv:
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
int main(int argc, char** argv) {
// parameters
std::string PATH_IMG_IN = "../img_test_rect.jpg";
std::string PATH_IMG_OUT = "../img_out.jpg";
// load image
cv::Mat img = cv::imread(PATH_IMG_IN, CV_LOAD_IMAGE_GRAYSCALE);
if (!img.data) // Check for invalid input
{
std::cout << "Could not open or find the image" << std::endl;
return -1;
}
// rotate image
cv::Mat img_new = cv::Mat::ones(img.size(), img.type()) * 0.5; // another type = CV_8U
cv::Mat mat_transform = (cv::Mat_<float>(2, 3) << 1, 0, 0.5, 0, 1, 0);
cv::warpAffine(img, img_new, mat_transform, img_new.size());
// show image
cv::imshow("Display window", img_new);
// save image
cv::imwrite(PATH_IMG_OUT, img_new);
// wait for the user to press any key:
cv::waitKey(0);
return 0;
}

img viewer with Qt

I'm trying to create an application based on model/view concept.
i need to open some directory, find all imgs in it and show them in MainWindow (subclass of QMainWindow).
The architecture is something like this:
1) via QDir create QStringList of "good" file names (using file names filter by extentions).
2) create QStandardItemModel and fill it with QStandardItem (QIcon(QImage(fileName).scaled(QSize)), fileName).
3) use QListView to show data from the model.
but there is some problems.
first of all - theModel.columnCount is, e.g., 52 but only one picture is shown on the screen and without its name.
can someone help me:
1) how to fill model correctly? my approach:
QDir dirs(dir);
QStringList imgs = dirs.entryList(QStringList() << "*.jpg" << "*.jpeg" << "*.bmp" << "*.png");
itemModel->clear();
QList<QStandardItem *> listItem;
for(int i = 0; i < imgs.count(); ++i){
QImage image = QImage(dir + "/" + imgs.at(i)).scaled(QSize(size().width()/4, size().height()/4));
QStandardItem *item = new QStandardItem();
item->setIcon(QIcon(QPixmap::fromImage(image)));
item->setData(imgs.at(i));
listItem << item;
}
itemModel->appendRow(listItem);
this code is in one slot of the MainWindow class.
2) as I understand, my view is automatically updated, so it should show all data from the model.
am I right, or some code is necessary?
3) maybe I haven't done somethings in initialization of the model and the view (the code is in te constructor of class MainWindow):
itemModel = new QStandardItemModel(this);
listView = new QListView(this);
listView->setModel(itemModel);
// listView->setFlow(QListView::LeftToRight);
// listView->setLayoutMode(QListView::Batched);
listView->setViewMode(QListView::IconMode);
listView->setResizeMode(QListView::Adjust);
// listView->setGridSize(QSize(size().width()/4, size().height()/4));
listView->setIconSize(QSize(size().width()/4, size().height()/4));
setCentralWidget(listView);
Since you determined that you needed appendColumn the last bit would be to add the QIcon as data with the Qt::DecorationRole. The follow works for me for viewing images in the same folder the program is run (though I don't know why it is shown with a grid layout).
#include <QApplication>
#include <QStandardItemModel>
#include <QListView>
#include <QDir>
#include <QStringList>
#include <QList>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStandardItemModel* itemModel = new QStandardItemModel();
QListView* listView = new QListView();
QDir dirs(".");
QStringList imgs = dirs.entryList(QStringList() << "*.jpg" << "*.jpeg" << "*.bmp" << "*.png");
QList<QStandardItem *> listItem;
for(int i = 0; i < imgs.count(); ++i){
QImage image = QImage(dirs.absoluteFilePath(imgs.at(i))).scaled(QSize(80, 60));
QStandardItem *item = new QStandardItem();
item->setData(QVariant(QPixmap::fromImage(image)), Qt::DecorationRole);
listItem << item;
}
itemModel->appendColumn(listItem);
listView->setModel(itemModel);
listView->setViewMode(QListView::IconMode);
listView->show();
a.exec();
}

QT: Qtableview wrapping text

I am working with QtableView of Qt. I am facing one problem. I am not able to fix the content in to complete cell . In my case i have fix size of column and rows can be stretched. following is sample code
#include <QApplication>
#include"QStandardItemModel"
#include"QTableView"
#include"QStandardItem"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStandardItemModel *model = new QStandardItemModel(8,3);
QTableView * pQTableView = new QTableView();
for(int r = 0;r<8;r++)
for(int c = 0; c<3; c++)
{
QModelIndex index1= model->index(r,c);
QVariant value("Swaminarayan maharaj");
model->setData(index1, value,Qt::DisplayRole );
QVariant value1( Qt::AlignCenter);
model->setData(index1, value1,Qt::TextAlignmentRole );
}
pQTableView->resize(400,400);
pQTableView->setModel(model);
pQTableView->setColumnWidth(0, 100);
pQTableView->setColumnWidth(1, 100);
pQTableView->setColumnWidth(2, 100);
pQTableView->show();
return a.exec();
}
As you can see i wants each cell to have "Swaminarayan maharaj".But Swaminarayan shold be in first line of the cell and "maharaj" in second line. Inshort each cell shold display content in two lines.
In folllowing link i found Qt::TextWordWrap but i am not able to use in my code
http://www.qtcentre.org/threads/27839-For-Qt-4-6-x-how-to-auto-size-text-to-fit-in-a-specified-width

Resources