Qt Unresolved External Symbol - c++

I have classes, ImageLabel, and ChoiceLabel. ChoiceLabel inherits from ImageLabel. When I try to make a new ChoiceLabel, I get an Unresolved External Symbol error. Here are the relevant files:
imagelabel.h
#ifndef IMAGELABEL_H
#define IMAGELABEL_H
#include <QLabel>
class QPixmap;
class QStringList;
class QFileDialog;
class QResizeEvent;
class ImageLabel : public QLabel
{
Q_OBJECT
public:
explicit ImageLabel(QWidget *parent = 0);
protected:
virtual int heightForWidth( int width ) const;
virtual QSize sizeHint() const;
QPixmap scaledPixmap() const;
void setPixmap ( const QPixmap & );
void resizeEvent(QResizeEvent *);
private:
QPixmap pix;
};
#endif // IMAGELABEL_H
choicelabel.h
#ifndef CHOICELABEL_H
#define CHOICELABEL_H
class QStringList;
class ChoiceLabel : public ImageLabel
{
Q_OBJECT
public:
ChoiceLabel();
private:
QStringList *imageFiles;
void mousePressEvent(QMouseEvent *);
void keyPressEvent(QKeyEvent *);
void focusInEvent(QFocusEvent *);
void focusOutEvent(QFocusEvent *);
};
#endif // CHOICELABEL_H
mainwindow.cpp
#include "mainwindow.h"
#include "imagelabel.h"
#include "choicelabel.h"
#include <QGridLayout>
#include <qDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
choiceLabelA = new ChoiceLabel; //the problem occurs here
resultLabel = new ImageLabel;
centralWidget = new QWidget(this);
this->setCentralWidget(centralWidget);
gridLayout = new QGridLayout(centralWidget);
gridLayout->addWidget(resultLabel);
}
EDIT:
imagelabel.cpp
#include "imagelabel.h"
#include <QDebug>
ImageLabel::ImageLabel(QWidget *parent) :
QLabel(parent)
{
setMinimumSize(250,250);
setAlignment(Qt::AlignCenter | Qt::AlignCenter);
setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
QPixmap initialPixmap(250, 250);
initialPixmap.fill(Qt::black);
setPixmap(initialPixmap);
}
void ImageLabel::setPixmap ( const QPixmap & p)
{
pix = p;
QLabel::setPixmap(scaledPixmap());
}
QPixmap ImageLabel::scaledPixmap() const
{
return pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
int ImageLabel::heightForWidth( int width ) const
{
return pix.isNull() ? this->height() : ((qreal)pix.height()*width)/pix.width();
}
QSize ImageLabel::sizeHint() const
{
int w = this->width();
return QSize( w, heightForWidth(w) );
}
void ImageLabel::resizeEvent(QResizeEvent *)
{
if(!pix.isNull())
QLabel::setPixmap(scaledPixmap());
}
choicelabel.cpp
#include "choicelabel.h"
#include <QStringList>
#include <QFileDialog>
#include <QFrame>
ChoiceLabel::ChoiceLabel():
imageFiles()
{
setFocusPolicy(Qt::StrongFocus);
}
void ChoiceLabel::mousePressEvent(QMouseEvent *)
{
QFileDialog dialog(this);
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setNameFilter("Images (*.png *.jpg)");
dialog.setDirectory("C:/Users/FrankFritz/Desktop/qt/uglypictures");
if (dialog.exec()){
imageFiles = dialog.selectedFiles();
QPixmap pixmap = imageFiles->first();
setPixmap(pixmap);
}
}
void ChoiceLabel::keyPressEvent(QKeyEvent *ev)
{
static int index(0);
if (ev->key() == Qt::Key_Right){
index = (index + 1) % imageFiles->length();
setPixmap( QPixmap(imageFiles->at(index)) );
}
if (ev->key() == Qt::Key_Left){
if (index == 0){
index = imageFiles->length() - 1;
}
else{
index = (index - 1) % imageFiles->length();
}
setPixmap( QPixmap(imageFiles->at(index)) );
}
}
void ChoiceLabel::focusInEvent(QFocusEvent *)
{
setFrameStyle(QFrame::StyledPanel);
}
void ChoiceLabel::focusOutEvent(QFocusEvent *)
{
setFrameStyle(QFrame::NoFrame);
}

Most probably
ChoiceLabel::ChoiceLabel():
imageFiles()
{
setFocusPolicy(Qt::StrongFocus);
}
ChoiceLabel::ChoiceLabel(QWidget *parent): ImageLabel(parent)
{
setFocusPolicy(Qt::StrongFocus);
}
Forgot to call the base class' constructor. Also forgot to specify a parent QWidget * for ChoiceLabel in its own constructor.
See What are the rules for calling the superclass constructor? for reference.

Related

Qt QGraphicsView Scrolling causes items to randomly disappear

I am having issues with a weird bug which occurs after you adjust the size of a QGraphicsItem.
Here is a YouTube video showing the issue: https://youtu.be/gp1lQTkPf54
In my application, a slider is used to adjust the horizontal zoom of all the regions on the QGraphicsScene. I have made sure to call prepareGeometryChange(); when I am changing the geometry of a region and call update(); but that has not helped. It seems to affect regions that are being rendered out of view from the user.
Code:
mainwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene *scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
RegionGraphicsItem *rgi = new RegionGraphicsItem(ui->graphicsView->scene());
itemList.append(rgi);
ui->graphicsView->scene()->addItem(rgi);
rgi->setHScaleFactor(ui->horizontalSlider->value());
}
void MainWindow::test() {
QWidget test;
test.show();
}
void MainWindow::on_horizontalSlider_valueChanged(int value)
{
for (int i = 0; i < itemList.size(); i++) {
itemList[i]->setHScaleFactor(value);
}
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "regiongraphicsitem.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QList<RegionGraphicsItem*> itemList;
private slots:
void on_pushButton_clicked();
void on_horizontalSlider_valueChanged(int value);
private:
void test();
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
regiongraphicsitem.cpp
#include "regiongraphicsitem.h"
RegionGraphicsItem::RegionGraphicsItem(QGraphicsScene *_scene) : QGraphicsItem()
{
regionColor = QColor::fromRgb(255,255,255);
setFlags(ItemIsMovable);
waveFormColor = regionColor.darker(80);
outlineColor = QColor("#0f0f0f");
selectedColor = selectedColor.lighter(30);
hScaleFactor = 100;
mainBrush = QBrush(regionColor);
mainPen = QPen(outlineColor, 1);
gridLength = 5;
height = 56;
oldPos = pos();
scene = _scene;
this->prepareGeometryChange();
gridLocation = 5;
setY((0 * 60) + 1);
}
QRectF RegionGraphicsItem::boundingRect() const
{
return QRectF(0, 0, float(gridLength * hScaleFactor), float(height));
}
void RegionGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);
QRectF rect = boundingRect();
painter->setBrush(mainBrush);
painter->setPen(mainPen);
painter->drawRoundedRect(rect, 5, 5);
painter->setPen(mainPen);
if (selected) {
painter->setBrush(QBrush(mainPen.color()));
painter->drawRoundedRect(QRect(rect.x(), rect.y(), rect.width(), 20), 5, 5);
painter->drawRect(QRect(rect.x(), rect.y() + 5, rect.width(), 15));
}
QFont font = scene->font();
font.setPixelSize(10);
font.setBold(true);
QFontMetricsF fontMetrics(font);
QString text = "TEST";
int heightFont = fontMetrics.boundingRect(text).height();
if (selected) {
painter->setPen(QPen(mainBrush.color(), 1));
}
painter->drawText(5, heightFont + 3, text);
if (pressed == false ) {
setX((gridLocation - 1) * hScaleFactor);
}
}
void RegionGraphicsItem::setHScaleFactor(int value) {
prepareGeometryChange();
hScaleFactor = value;
update();
}
regiongraphicsitem.h
#ifndef RegionGraphicsItem_H
#define RegionGraphicsItem_H
#include <QGraphicsItem>
#include <QColor>
#include <QBrush>
#include <QPen>
#include <QtGui/QPainter>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include <stdint.h>
class RegionGraphicsItem : public QGraphicsItem
{
public:
RegionGraphicsItem(QGraphicsScene *_scene);
float getGridLocation();
void setHScaleFactor(int value);
protected:
QColor outlineColor;
QColor selectedColor;
QColor regionColor;
QColor waveFormColor;
bool selected;
int penWidth;
int rounded;
QBrush mainBrush;
QBrush waveformBrush;
QPen mainPen;
int height;
float gridLength;
bool pressed = false;
QPointF oldPos, oldMousePos;
int oldTrackIndex;
float gridLocation;
QGraphicsScene *scene;
int oldHScaleFactor;
virtual QRectF boundingRect() const override;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
private:
int hScaleFactor;
};
#endif // RegionGraphicsItem_H
Steps to reproduce:
Add a RegionGraphicItem to the QGraphicsScene
Increase the slider until the region is off screen
Decrease the slider and the region will not be visible. <-- This is the issue.

Draggable pixmaps inside a QGraphicsScene of graphic items

I have a scene with a 12*4 grid with blocks of QGraphicsItems ,when i right click on the blocks I have a contexmenu that
can add icons inside the blocks my proplem is that
I can't fingure out how can I make those icons draggable to the other blocks inside the graphic scene ,I know there is the "Draggable Icons Example" but how can I implement that code to a graphic scene.
this is the mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsPathItem>
class QGraphicsSceneMouseEvent;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
bool eventFilter(QObject *, QEvent *);
~MainWindow();
private slots:
void showContextMenu(const QPoint&);
void addPixBlock();
private:
Ui::MainWindow *ui;
QGraphicsScene *scene;
QGraphicsItem *itemAt(const QPointF&);
int x;
int y;
QMenu *Menu;
QMenu *Submenu;
QAction *Picture;
QGraphicsPixmapItem* pix;
};
#endif // MAINWINDOW_H
the mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "block.h"
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include <QPainter>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene(this) ;
for(int row=-4;row<8;++row)
for(int column=0;column<4;++column)
{
Block *b = new Block;
scene->addItem(b);
b->setPos(row* 95,column*85);
}
ui->graphicsView->setScene(scene);
scene->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
QGraphicsItem* MainWindow::itemAt(const QPointF &pos)
{
QList<QGraphicsItem*> items = scene->items(QRectF(pos - QPointF(1,1),
QSize(3,3)));
foreach(QGraphicsItem *item, items)
if (item->type() > QGraphicsItem::UserType)
return item;
return 0;
}
bool MainWindow::eventFilter(QObject *o, QEvent *e)
{
QGraphicsSceneMouseEvent *me = (QGraphicsSceneMouseEvent*) e;
switch ((int) e->type()){
case QEvent::GraphicsSceneMousePress:{
switch ((int) me->button()){
case Qt::RightButton:{
QGraphicsItem *item = itemAt(me->scenePos());
if (item && item->type() == Block::Type){
x=item->scenePos().x();
y=item->scenePos().y();
showContextMenu(item->scenePos().toPoint());
}
break;
}
}
break;
}
}
return QObject::eventFilter(o, e);
}
void MainWindow::showContextMenu(const QPoint &pos)
{
Menu= new QMenu("Menu");
Submenu=Menu->addMenu(QIcon(":/img/pix.png"),"Pix");
Picture =Submenu->addAction(QIcon(":/img/pix.png"),"Pix");
connect(Picture, SIGNAL(triggered()), this, SLOT(addPixBlock()));
Menu->exec(QCursor::pos());
}
void MainWindow::addPixBlock()
{
QPixmap pixmap(":/img/pix.png");
pix = scene->addPixmap(pixmap.scaled(70,50));
pix->setPos(x,y);
}
the block.h
#ifndef BLOCK_H
#define BLOCK_H
#include <QGraphicsPathItem>
class QGraphicsSceneMouseEvent;
class Block : public QGraphicsPathItem
{
public:
enum { Type = QGraphicsItem::UserType + 3 };
int type() const { return Type; }
Block(QGraphicsItem *parent = 0);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget
*widget);
bool eventFilter(QObject *, QEvent *);
};
#endif // BLOCK_H
the Block.cpp
#include "block.h"
#include <QPainter>
#include <QtWidgets>
class QGraphicsSceneMouseEvent;
Block::Block(QGraphicsItem *parent)
: QGraphicsPathItem(parent)
{
QPainterPath p;
//<->,|,<->,|,roundness
p.addRoundedRect(0,0,80,50, 5, 5);
setPath(p);
setAcceptDrops(true);
setAcceptedMouseButtons(Qt::LeftButton);
}
void Block::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
painter->setPen(QPen(QColor(67, 141, 220)));
painter->setBrush(QColor(67, 141, 220,100));
painter->drawPath(path());
}
First of all if you want to place a QGraphicsPixmapItem on top of another item, a better option is to set it as your parentItem.
On the other hand we can use an event filter but a better option in this case is to implement a custom QGraphicsScene, and when pressing with the left key it allows to drag the item, for that we use QDrag and we pass the data of the item, then we overwrite the event dropEvent where we will obtain the item and establish a new parent.
graphicsscene.h
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
class QMenu;
class QAction;
class GraphicsScene : public QGraphicsScene
{
public:
using QGraphicsScene::QGraphicsScene;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void dropEvent(QGraphicsSceneDragDropEvent *event) override;
private:
QGraphicsPixmapItem *findPixmapItem(QGraphicsItem *item);
void createDrag(const QPointF &pos, QWidget *widget, QGraphicsItem *item);
void showContextMenu(const QPointF &pos);
void addPixBlock(QGraphicsItem *item);
QMenu *menu;
QMenu *submenu;
QAction *picture;
QGraphicsPixmapItem *pix;
};
#endif // GRAPHICSSCENE_H
graphicsscene.cpp
#include "graphicsscene.h"
#include <QDrag>
#include <QGraphicsItem>
#include <QGraphicsSceneMouseEvent>
#include <QMenu>
#include <QMimeData>
#include <QWidget>
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
auto its = items(QRectF(event->scenePos() - QPointF(1,1), QSize(3,3)));
auto val = std::find_if(its.constBegin(), its.constEnd(), [](auto const& it){
return it->type() > QGraphicsItem::UserType;
});
if(val == its.constEnd())
return;
if(event->button() == Qt::RightButton){
showContextMenu(event->scenePos());
}
else{
createDrag(event->scenePos(), event->widget(), *val);
}
}
void GraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
{
QByteArray byteArray = event->mimeData()->data("Item");
QGraphicsPixmapItem * item = *reinterpret_cast<QGraphicsPixmapItem**>(byteArray.data());
QGraphicsItem *item_parent = itemAt(event->scenePos(), QTransform());
item->setParentItem(item_parent);
}
QGraphicsPixmapItem *GraphicsScene::findPixmapItem(QGraphicsItem *item){
auto chs = item->childItems();
auto val = std::find_if(chs.constBegin(), chs.constEnd(), [](auto const& it){
return static_cast<QGraphicsPixmapItem *>(it) != Q_NULLPTR;
});
return val == chs.constEnd() ? Q_NULLPTR : static_cast<QGraphicsPixmapItem *>(*val);
}
void GraphicsScene::createDrag(const QPointF &pos, QWidget *widget, QGraphicsItem *item){
QGraphicsPixmapItem *pix = findPixmapItem(item);
if(pix == Q_NULLPTR)
return;
QByteArray byteArray(reinterpret_cast<char*>(&pix),sizeof(QGraphicsPixmapItem*));
QDrag *drag = new QDrag(widget);
QMimeData * mimeData = new QMimeData;
mimeData->setData("Item",byteArray);
drag->setMimeData(mimeData);
drag->setHotSpot(pos.toPoint()-pix->scenePos().toPoint());
drag->setPixmap(pix->pixmap());
drag->start();
}
void GraphicsScene::showContextMenu(const QPointF &pos)
{
QGraphicsItem *item = itemAt(pos, QTransform());
menu= new QMenu("Menu");
submenu = menu->addMenu(QIcon(":/img/pix.png"),"Pix");
picture = submenu->addAction(QIcon(":/img/pix.png"),"Pix");
connect(picture, &QAction::triggered, [item, this](){
addPixBlock(item);
});
menu->exec(QCursor::pos());
}
void GraphicsScene::addPixBlock(QGraphicsItem *item)
{
if(findPixmapItem(item))
return;
QPixmap pixmap(":/img/pix.png");
pix = addPixmap(pixmap.scaled(70,50));
if(pix->parentItem() != item)
pix->setParentItem(item);
}
Then we establish that new scene and add the Blocks.
The complete example can be found in the following link

Transferring data from one form to another in Qt?

there was such problem. I have a main and auxiliary form. With the second form, I take two values: the index and the color. I'm transferring to the main form. I get the values ​​in the "setParametr" method. But I can not get them in the "paintEvent" method. QDebug show that the method "setParametr" got the values. When I check the values ​​in "on_pushButton_clicked()" values is 0. What could be the problem. Just started to study Qt
dialog.h
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
void setcolor(int);
int getcolor();
void setindex(int);
int getindex();
private slots:
void ColorIndex();
void on_pushButton_clicked();
private:
Ui::Dialog *ui;
int squareColor;
int Index;
};
dialog.cpp
#include "ui_dialog.h"
#include "dialog.h"
#include "mainwindow.h"
#include "QDebug"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
//connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(ColorIndex()));
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::setcolor(int color)
{
squareColor = color;
}
int Dialog::getcolor()
{
return squareColor;
}
void Dialog::setindex(int index)
{
Index = index;
}
int Dialog::getindex()
{
return Index;
}
void Dialog::on_pushButton_clicked()
{
MainWindow *main = new MainWindow();
if(ui->radioButton->isChecked()){
setcolor(1);
}
if(ui->radioButton_2->isChecked()){
setcolor(2);
}
if(ui->radioButton_3->isChecked()){
setcolor(3);
}
if(ui->comboBox->currentIndex()==0)
{
setindex(1);
}
if(ui->comboBox->currentIndex()==1)
{
setindex(2);
}
if(ui->comboBox->currentIndex()==2)
{
setindex(3);
}
if(ui->comboBox->currentIndex()==3)
{
setindex(4);
}
qDebug() << QString::number(getcolor());
qDebug() << QString::number(getindex());
main->SetParametr(getindex(),getcolor());
}
mainwindow.h
#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QPainterPath>
#include <QColor>
#include <QColorDialog>
#include <QPushButton>
#include <QMainWindow>
#include "dialog.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setColor(int);
int getColor();
void setIndex(int);
int getIndex();
private:
Dialog *dial = new Dialog();
int fIndex;
int fColor;
private slots:
void on_actionMy_Dialog_triggered();
void paintEvent(QPaintEvent *event);
void on_pushButton_clicked();
signals:
void SetParametr(int index, int color);
private:
Ui::MainWindow *ui;
void onInit();
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"
#include "dialog.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
fColor = 0;
fIndex =0;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::SetParametr(int index, int color)
{
fIndex = index;
fColor = color;
qDebug() << QString::number(fColor) + "s";
qDebug() << QString::number(fIndex);
}
/*void MainWindow::setColor(int _color)
{
fColor = _color;
}
int MainWindow::getColor()
{
return fColor;
}
void MainWindow::setIndex(int _index)
{
fIndex = _index;
}
int MainWindow::getIndex()
{
return fIndex;
}
*/
void MainWindow::paintEvent(QPaintEvent *event)
{
QColor red1;
if(fColor==1){
red1 = Qt::red;
}
if(fColor == 2){
red1 = Qt::blue;
}
if(fColor == 3){
red1 = Qt::green;
}
int index1;
if(fIndex == 0)
{
index1 = 0;
}
if(fIndex == 1)
{
index1 = 1;
}
if(fIndex == 2)
{
index1 = 2;
}
if(fIndex == 3)
{
index1 = 3;
}
Q_UNUSED(event);
QPainter painter(this);
if(index1 == 0)
{
painter.setBrush(QBrush(red1, Qt::SolidPattern));
painter.drawEllipse(100, 50, 150, 150);
}
if(index1 == 1)
{
painter.setBrush(QBrush(red1, Qt::SolidPattern));
painter.drawRect(50, 50, 250, 150);
}
if(index1 == 2)
{
painter.setBrush(QBrush(red1, Qt::SolidPattern));
QPolygon polygon;
polygon<<QPoint(175,50)<<QPoint(50,200)<<QPoint(300,200);
painter.drawPolygon(polygon);
}
if(index1 == 3)
{
painter.setBrush(QBrush(red1, Qt::SolidPattern));
painter.drawRect(100, 50, 150, 150);
}
}
void MainWindow::on_actionMy_Dialog_triggered()
{
dial->show();
}
void MainWindow::on_pushButton_clicked()
{
qDebug() << QString::number(fColor);
qDebug() << QString::number(fIndex);
}

Dynamic QLabel misplacing in UI

I'm trying to create a program that accepts images through drag and drop and shows those images on my UI, then I want to rename them and save them.
I got the drag and drop to work, but I have some issues with my Image placement and I can't seem to find where I'm making my mistake.
In the image you see my UI during runtime, in the top left you can see a part of the image I dragged into the green zone(this is my drag and drop zone that accepts images). The position I actually want it to be in should be the red square. The green zone is a Dynamic created object called Imagehandler that I created to handle the drag and drop of the images. The Red square is my own class that inherits from QLabel, I called it myiconclass. This class should hold the actual image data.
I think my mistake has to do with the layouts, but I can't see it.
Could I get some help with this please?
Imagehandler.h
#ifndef IMAGEHANDLER_H
#define IMAGEHANDLER_H
#include <QObject>
#include <QWidget>
#include <QLabel>
#include <QDrag>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QList>
#include <QDebug>
//this class is designed to help me take in the images with drag and drop
class ImageHandler : public QWidget
{
Q_OBJECT
public:
explicit ImageHandler(QWidget *parent = nullptr);
QList<QImage> getImageListMemory() const;
void setImageListMemory(const QList<QImage> &value);
QList<QUrl> getUrlsMemory() const;
void setUrlsMemory(const QList<QUrl> &value);
private:
//QWidget Icon;
QLabel Icon;
QList <QImage> imageListMemory;
QList <QUrl> urlsMemory;
protected:
void dragEnterEvent(QDragEnterEvent * event);
void dragLeaveEvent(QDragLeaveEvent * event);
void dragMoveEvent(QDragMoveEvent * event);
void dropEvent(QDropEvent * event);
signals:
void transferImageSignal(QList <QImage>);
public slots:
};
#endif // IMAGEHANDLER_H
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QImageReader>
#include <QList>
#include <QWidget>
#include <QLabel>
#include <myiconclass.h>
#include <imagehandler.h>
#include <QGridLayout>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QList<QImage> getImageListMemory() const;
void setImageListMemory(const QList<QImage> &value);
private:
Ui::MainWindow *ui;
QLabel Icon;
QList <QImage> imageListMemory;
QList <QUrl> urlsMemory;
QList<QWidget *> labelList;
ImageHandler * ImageHandlerMemory;
QGridLayout * grid2;
QList <MyIconClass *> memory;
signals:
public slots:
void setIconSlot(QList <QImage>);
};
#endif // MAINWINDOW_H
myiconclass.h
#ifndef MYICONCLASS_H
#define MYICONCLASS_H
#include <QWidget>
#include <QLabel>
//this class is based on a Qlabel and is only made so it can help me with the actual images, gives me more members if I need it
class MyIconClass : public QLabel
{
Q_OBJECT
public:
explicit MyIconClass(QWidget *parent = nullptr);
int getMyNumber() const;
void setMyNumber(int value);
private:
int myNumber;
signals:
public slots:
};
#endif // MYICONCLASS_H
imagehandler.cpp
#include "imagehandler.h"
ImageHandler::ImageHandler(QWidget *parent) : QWidget(parent)
{
setAcceptDrops(true);
}
QList<QImage> ImageHandler::getImageListMemory() const
{
return imageListMemory;
}
void ImageHandler::setImageListMemory(const QList<QImage> &value)
{
imageListMemory = value;
}
QList<QUrl> ImageHandler::getUrlsMemory() const
{
return urlsMemory;
}
void ImageHandler::setUrlsMemory(const QList<QUrl> &value)
{
urlsMemory = value;
}
void ImageHandler::dragEnterEvent(QDragEnterEvent * event)
{
event->accept();
}
void ImageHandler::dragLeaveEvent(QDragLeaveEvent * event)
{
event->accept();
}
void ImageHandler::dragMoveEvent(QDragMoveEvent * event)
{
event->accept();
}
void ImageHandler::dropEvent(QDropEvent * event)
{
QList <QImage> imageList2;
QList <QUrl> urls;
QList <QUrl>::iterator i;
urls = event->mimeData()->urls();
//imageList.append(event->mimeData()->imageData());
foreach (const QUrl &url, event->mimeData()->urls())
{
QString fileName = url.toLocalFile();
qDebug() << "Dropped file:" << fileName;
qDebug()<<url.toString();
QImage img;
if(img.load(fileName))
{
imageList2.append(img);
}
}
emit transferImageSignal(imageList2);
this->setUrlsMemory(urls);
this->setImageListMemory(imageList2);
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ImageHandler * handler = new ImageHandler(this);
handler->show();
QGridLayout *grid = new QGridLayout;
grid->addWidget(handler, 0, 0);
ui->groupBoxIcon->setLayout(grid);
ImageHandlerMemory = handler;
//connect(handler,SIGNAL(handler->transferImageSignal(QList <QUrl>)),this,SLOT(setIconSlot(QList <QUrl>)));
connect(handler,SIGNAL(transferImageSignal(QList<QImage>)),this,SLOT(setIconSlot(QList<QImage>)));
}
MainWindow::~MainWindow()
{
delete ui;
}
QList<QImage> MainWindow::getImageListMemory() const
{
return imageListMemory;
}
void MainWindow::setImageListMemory(const QList<QImage> &value)
{
imageListMemory = value;
}
void MainWindow::setIconSlot(QList<QImage> images)
{
printf("succes!");
this->setImageListMemory(images); //save the images to memory
QGridLayout *grid = new QGridLayout; //create the grid layout I want my images to be in
// create counters to remember the row and column in the grid
int counterRow =0;
int counterColumn =0;
int counter3 =0;
int counterImages = 0;
//iterate over each image in the list
QList <QImage>::iterator x;
for(x = imageListMemory.begin(); x != imageListMemory.end(); x++)
{
MyIconClass * myLabel = new MyIconClass(this); //create an object of my own class (which is a Qlabel with an int member)
QPixmap pixmap(QPixmap::fromImage(*x)); //create a pixmap from the image in the iteration
myLabel->setPixmap(pixmap); //set the pixmap on my label object
myLabel->show();
memory.append(myLabel); //add it to the memory so I can recal it
counterImages++;
}
while(counter3 < images.count())
{
grid2->addWidget(memory.value(counter3), counterRow, counterColumn);
counterColumn++;
counter3++;
if(counterColumn >= 5)
{
counterRow++;
counterColumn =0;
}
}
if(ImageHandlerMemory->layout() == 0)
{
ImageHandlerMemory->setLayout(grid2);
}
}
myiconclass.cpp
#include "myiconclass.h"
MyIconClass::MyIconClass(QWidget *parent) : QLabel(parent)
{
}
int MyIconClass::getMyNumber() const
{
return myNumber;
}
void MyIconClass::setMyNumber(int value)
{
myNumber = value;
}
As Benjamin T said I had to change this:
MyIconClass * myLabel = new MyIconClass(this);
into this:
MyIconClass * myLabel = new MyIconClass(ImageHandlerMemory);
Thanks Benjamin!
PS, I also had to add this line in my mainwindow constructor:
grid2 = new QGridLayout;

Designing a Qt Creator's SideBar in C++

I have created a class for making a sidebar just like in Qt Creator (one to the left). I am having no idea now to make it look exactly like the one in Qt creator as mine looks ugly!
The sidebar.h:
#ifndef _SIDEBAR_H_
#define _SIDEBAR_H_
#include <QVector>
#include <QString>
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <QPixmap>
#include <iostream>
class SideBar : public QWidget
{
public:
SideBar(QWidget *parent=nullptr);
void addIcon(const char *name);
void addIcon(QString &name);
private:
QVBoxLayout *_layout;
};
#endif // SIDEBAR_H
The sidebar.cpp
#include "sidebar.h"
#include <QPushButton>
#include <QIcon>
SideBar::SideBar(QWidget *parent) : QWidget(parent)
{
_layout = new QVBoxLayout(this);
setLayout(_layout);
}
void SideBar::addIcon(const char *name)
{
QString str(name);
addIcon(str);
}
void SideBar::addIcon(QString &file)
{
QPushButton *button = new QPushButton(this);
QPixmap pixmap(file);
QIcon buttonIcon(pixmap);
button->setIcon(buttonIcon);
// button->setIconSize(pixmap.rect().size());
_layout->addWidget(button);
}
This is one i want:
And this is one i got:
A possible solution is to use QAction to handle the clicks and icons, overwriting the methods paintEvent, mousePressEvent, mouseMoveEvent, leaveEvent, changing the colors regarding the state in which the widget is.
sidebar.h
#ifndef SIDEBAR_H
#define SIDEBAR_H
#include <QAction>
#include <QWidget>
class SideBar : public QWidget
{
Q_OBJECT
public:
explicit SideBar(QWidget *parent = nullptr);
void addAction(QAction *action);
QAction *addAction(const QString &text, const QIcon &icon = QIcon());
QSize minimumSizeHint() const;
signals:
public slots:
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void leaveEvent(QEvent * event);
QAction *actionAt(const QPoint &at);
private:
QList<QAction *> mActions;
QAction *mCheckedAction;
QAction *mOverAction;
};
#endif // SIDEBAR_H
sidebar.cpp
#include "sidebar.h"
#include <QPaintEvent>
#include <QPainter>
#include <QDebug>
#include <QEvent>
#define action_height 90
SideBar::SideBar(QWidget *parent) :
QWidget(parent), mCheckedAction(NULL), mOverAction(NULL)
{
setMouseTracking(true);
}
void SideBar::paintEvent(QPaintEvent *event)
{
QPainter p(this);
QFont fontText(p.font());
fontText.setFamily("Helvetica Neue");
p.setFont(fontText);
int action_y = 0;
p.fillRect(rect(), QColor(100, 100, 100));
for(auto action: mActions)
{
QRect actionRect(0, action_y, event->rect().width(), action_height);
if(action->isChecked())
{
p.fillRect(actionRect, QColor(35, 35, 35));
}
if(action == mOverAction){
p.fillRect(actionRect, QColor(150, 150, 150));
}
p.setPen(QColor(255, 255, 255));
QSize size = p.fontMetrics().size(Qt::TextSingleLine, action->text());
QRect actionTextRect(QPoint(actionRect.width()/2 - size.width()/2, actionRect.bottom()-size.height()-5), size);
p.drawText(actionTextRect, Qt::AlignCenter, action->text());
QRect actionIconRect(0, action_y + 10, actionRect.width(), actionRect.height()-2*actionTextRect.height()-10);
QIcon actionIcon(action->icon());
actionIcon.paint(&p, actionIconRect);
action_y += actionRect.height();
}
}
QSize SideBar::minimumSizeHint() const
{
return action_height*QSize(1, mActions.size());
}
void SideBar::addAction(QAction *action)
{
mActions.push_back(action);
action->setCheckable(true);
update();
}
QAction *SideBar::addAction(const QString &text, const QIcon &icon)
{
QAction *action = new QAction(icon, text, this);
action->setCheckable(true);
mActions.push_back(action);
update();
return action;
}
void SideBar::mousePressEvent(QMouseEvent *event)
{
QAction* tempAction = actionAt(event->pos());
if(tempAction == NULL || tempAction->isChecked())
return;
qDebug()<<"clicked";
if(mCheckedAction)
mCheckedAction->setChecked(false);
if(mOverAction == tempAction)
mOverAction = NULL;
mCheckedAction = tempAction;
tempAction->setChecked(true);
update();
QWidget::mousePressEvent(event);
}
void SideBar::mouseMoveEvent(QMouseEvent *event)
{
QAction* tempAction = actionAt(event->pos());
if(tempAction == NULL){
mOverAction = NULL;
update();
return;
}
if(tempAction->isChecked() || mOverAction == tempAction)
return;
mOverAction = tempAction;
update();
QWidget::mouseMoveEvent(event);
}
void SideBar::leaveEvent(QEvent * event)
{
mOverAction = NULL;
update();
QWidget::leaveEvent(event);
}
QAction* SideBar::actionAt(const QPoint &at)
{
int action_y = 0;
for(auto action: mActions)
{
QRect actionRect(0, action_y, rect().width(), action_height);
if(actionRect.contains(at))
return action;
action_y += actionRect.height();
}
return NULL;
}
#undef action_height
The sample code is here.
Screenshots: