C++ Qt5.11 error :" C2661: No overloaded function takes 3 arguments" - c++

I am new to Qt and when I tried to compile and run a Qt program from "Foundations of Qt Development " Chapter 7, see
http://www.java2s.com/Code/Cpp/Qt/QGraphicsViewQGraphicsItemandQGraphicsScene.htm
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QGLWidget>
QGraphicsItem *createItem( int x, QGraphicsScene *scene )
{
QGraphicsRectItem *rectItem = new QGraphicsRectItem( QRect( x+40, 40, 120, 120 ), 0, scene );
rectItem->setPen( QPen(Qt::black) );
rectItem->setBrush( Qt::gray );
QGraphicsRectItem *innerRectItem = new QGraphicsRectItem( QRect( x+50, 50, 45, 100 ), rectItem, scene );
innerRectItem->setPen( QPen(Qt::black) );
innerRectItem->setBrush( Qt::white );
QGraphicsEllipseItem *ellipseItem = new QGraphicsEllipseItem( QRect( x+105, 50, 45, 100 ), rectItem, scene );
ellipseItem->setPen( QPen(Qt::black) );
ellipseItem->setBrush( Qt::white );
return rectItem;
}
int main( int argc, char **argv )
{
QApplication app( argc, argv );
QGraphicsScene scene( QRect( 0, 00, 1000, 200 ) );
QGraphicsItem *item1 = createItem( 0, &scene );
QGraphicsItem *item2 = createItem( 200, &scene );
item2->translate( 300, 100 );
item2->rotate( 30 );
item2->translate( -300, -100 );
QGraphicsItem *item3 = createItem( 400, &scene );
item3->translate( 500, 100 );
item3->scale( 0.5, 0.7 );
item3->translate( -500, -100 );
QGraphicsItem *item4 = createItem( 600, &scene );
item4->translate( 700, 100 );
item4->shear( 0.1, 0.3 );
item4->translate( -700, -100 );
QGraphicsItem *item5 = createItem( 800, &scene );
item5->translate( 900, 100 );
item5->scale( 0.5, 0.7 );
item5->rotate( 30 );
item5->shear( 0.1, 0.3 );
item5->translate( -900, -100 );
QGraphicsView view;
view.setScene( &scene );
view.setViewport( new QGLWidget() );
view.show();
return app.exec();
}
I always got the error info " error: C2661: “QGraphicsRectItem::QGraphicsRectItem”: "No overloaded function takes 3 arguments".I tried again and again but all the same.Could somebody help me solving this problem? Thanks.
I am using Qt5.11.0 and MSVC2017 and Windows 10 pro X64.

The code you sample is inconsistent with Qt5, an updated translation is as follows:
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QOpenGLWidget>
static QGraphicsItem *createItem( int x, QGraphicsScene *scene )
{
QGraphicsRectItem *rectItem = new QGraphicsRectItem(QRectF( x+40, 40, 120, 120 ));
scene->addItem(rectItem);
rectItem->setPen(QPen(Qt::black));
rectItem->setBrush( Qt::gray );
QGraphicsRectItem *innerRectItem = new QGraphicsRectItem( QRect( x+50, 50, 45, 100 ), rectItem);
innerRectItem->setPen( QPen(Qt::black) );
innerRectItem->setBrush( Qt::white );
QGraphicsEllipseItem *ellipseItem = new QGraphicsEllipseItem( QRect( x+105, 50, 45, 100 ), rectItem);
ellipseItem->setPen( QPen(Qt::black) );
ellipseItem->setBrush( Qt::white );
return rectItem;
}
int main( int argc, char **argv )
{
QApplication app( argc, argv );
QGraphicsScene scene( QRect( 0, 00, 1000, 200 ) );
QGraphicsItem *item1 = createItem( 0, &scene );
QGraphicsItem *item2 = createItem( 200, &scene );
QTransform tr2;
tr2.translate( 300, 100 );
tr2.rotate( 30 );
tr2.translate( -300, -100 );
item2->setTransform(tr2);
QGraphicsItem *item3 = createItem( 400, &scene );
QTransform tr3;
tr3.translate( 500, 100 );
tr3.scale( 0.5, 0.7 );
tr3.translate( -500, -100 );
item3->setTransform(tr3);
QGraphicsItem *item4 = createItem( 600, &scene );
QTransform tr4;
tr4.translate( 700, 100 );
tr4.shear( 0.1, 0.3 );
tr4.translate( -700, -100 );
item4->setTransform(tr4);
QGraphicsItem *item5 = createItem( 800, &scene );
QTransform tr5;
tr5.translate( 900, 100 );
tr5.scale( 0.5, 0.7 );
tr5.rotate( 30 );
tr5.shear( 0.1, 0.3 );
tr5.translate( -900, -100 );
item5->setTransform(tr4);
QGraphicsView view;
view.setScene( &scene );
view.setViewport( new QOpenGLWidget() );
view.show();
return app.exec();
}
*.pro
QT += core gui widgets opengl
TEMPLATE = app
CONFIG += c++11
SOURCES += main.cpp

It means exactly what it says, that you are trying to call the constructor of QGraphicsRectItem with three arguments:
... = new QGraphicsRectItem(QRect(x+40, 40, 120, 120), 0, scene);
\______________________/ | \___/
1 2 3
If you look at the documentation, you'll see that no such constructor exists:
QGraphicsRectItem(QGraphicsItem *parent = nullptr);
QGraphicsRectItem(const QRectF &rect, QGraphicsItem *parent = nullptr)
QGraphicsRectItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent = nullptr);
The first has one optional argument (so zero or one), the second has one mandatory and one optional (so one or two) and the third has four mandatory and one optional (so four or five).
If you examine that previous paragraph closely, you'll notice that one thing missing is the word "three" :-) I'd suggest ditching that tutorial since it's very old. Qt 4.2 (when that class was first introduced) did have a three-argument version which included the scene, but that was very short-lived and removed in 4.3.
For 5.11, further reading of the linked documentation shows up the fact that the (my emphasis):
QGraphicsRectItem class provides a rectangle item that you can add to a QGraphicsScene.
Hence the correct way to do what you appear to need is:
QGraphicsRectItem *rectItem = new QGraphicsRectItem(QRectF(x+40, 40, 120, 120));
scene->addItem(rectItem);

Related

QwtPlotSpectrogram with log scales

I want to put logarithmic a scale next to spectrogram. I want the displayed image to be the same as for the linear data. The code for the version with linear scales looks like this:
#include <QApplication>
#include <QMainWindow>
#include <qwt_plot.h>
#include <qwt_plot_spectrogram.h>
#include <qwt_matrix_raster_data.h>
#include <qwt_color_map.h>
#include <qwt_scale_engine.h>
int main( int argc, char* argv[] ) {
QApplication app( argc, argv );
QMainWindow wnd;
QVector<double> heat_values( 100 * 100 );
for( int n = 0; n < 100 * 100; ++n ) {
heat_values[n] = ( n % 100 ) + n / 100;
};
QwtPlotSpectrogram heat;
auto heat_data = std::make_unique<QwtMatrixRasterData>();
heat_data->setValueMatrix( heat_values, 100 );
heat_data->setResampleMode(
QwtMatrixRasterData::ResampleMode::NearestNeighbour );
heat_data->setInterval( Qt::XAxis, QwtInterval( 0, 100.0 ) );
heat_data->setInterval( Qt::YAxis, QwtInterval( 0, 100.0 ) );
heat_data->setInterval( Qt::ZAxis, QwtInterval( 0, 200.0 ) );
heat.setDisplayMode( QwtPlotSpectrogram::DisplayMode::ImageMode, true );
heat.setColorMap( new QwtLinearColorMap( Qt::white, Qt::black ) );
heat.setData( heat_data.release() );
QwtPlot p;
p.setAutoDelete( false );
heat.attach( &p );
p.repaint();
wnd.setCentralWidget( &p );
wnd.resize( 400, 300 );
wnd.show();
return QApplication::exec();
}
and produces the expected result.
However, I want the same image but with different scales, for example logarithmic scales from 1 to 101. But after I change the scales like this:
p.setAxisScaleEngine( QwtPlot::yLeft, new QwtLogScaleEngine() );
p.setAxisScale( QwtPlot::yLeft, 1.0, 101.0 );
p.setAxisScaleEngine( QwtPlot::xBottom, new QwtLogScaleEngine() );
p.setAxisScale( QwtPlot::xBottom, 1.0, 101.0 );
then the spectrogram is all messed up.
Does anyone know how to just change the displayed scale?
msvc 2017, x64, qwt 6.1.4, qt 5.12.2
Edit:
I can get half way there by defining my own RasterData and mapping the coordinates back into bins, but it's still missing the inverse transformation, so the displayed data is a 'log' version of the original.
class RasterData : public QwtRasterData
{
public:
double value( double const x, double const y ) const override {
int const ix = std::min<int>( std::max<int>( 0, x ), m_cols-1 );
int const iy = std::min<int>( std::max<int>( 0, y ), m_cols-1 );
return m_values[iy * m_cols + ix];
}
void setValueMatrix( QVector<double> const& values, int const cols ) {
m_values = values;
m_cols = cols;
}
private:
QVector<double> m_values;
int m_cols;
};
then result then looks like this:
But essentially I want to avoid all of these tranformations. I want it to just transform the image data passed in via setValueMatrix into an image using the set color map and stretch that image to fit the plot.
The best way I found to make this work is by deriving from QwtPlotSpectrogram and changing the transformation to linear for the call to draw.
class PlotSpectrogram : public QwtPlotSpectrogram {
public:
void draw(
QPainter* painter,
QwtScaleMap const& xMap,
QwtScaleMap const & yMap,
QRectF const& canvasRect ) const override {
QwtScaleMap xMapLin( xMap );
QwtScaleMap yMapLin( yMap );
auto const xi = data()->interval( Qt::XAxis );
auto const yi = data()->interval( Qt::YAxis );
auto const dx = xMapLin.transform( xMap.s1() );
xMapLin.setScaleInterval( xi.minValue(), xi.maxValue() );
auto const dy = yMapLin.transform( yMap.s2() );
yMapLin.setScaleInterval( yi.minValue(), yi.maxValue() );
xMapLin.setTransformation( new QwtNullTransform() );
yMapLin.setTransformation( new QwtNullTransform() );
QwtPlotSpectrogram::draw(
painter, xMapLin, yMapLin, canvasRect.translated( dx, -dy ) );
}
};
With main altered for a scale log scale from 20..50 and using PlotSpectrogram
PlotSpectrogram heat;
auto heat_data = std::make_unique<QwtMatrixRasterData>();
heat_data->setValueMatrix( heat_values, 100 );
heat_data->setInterval( Qt::XAxis, QwtInterval( 0, 100.0 ) );
heat_data->setInterval( Qt::YAxis, QwtInterval( 0, 100.0 ) );
heat_data->setInterval( Qt::ZAxis, QwtInterval( 0, 200.0 ) );
heat.setDisplayMode( QwtPlotSpectrogram::DisplayMode::ImageMode, true );
heat.setColorMap( new QwtLinearColorMap( Qt::white, Qt::black ) );
heat.setData( heat_data.release() );
QwtPlot p;
p.setAxisScaleEngine( QwtPlot::yLeft, new QwtLogScaleEngine() );
p.setAxisScale( QwtPlot::yLeft, 20.0, 50.0 );
p.setAxisScaleEngine( QwtPlot::xBottom, new QwtLogScaleEngine() );
p.setAxisScale( QwtPlot::xBottom, 20.0, 50.0 );
p.setAutoDelete( false );
heat.attach( &p );
I then get the desired output
QwtPlotMatrixRasterData is not working with non linear scales !
When using QwtRasterData instead everything will work out of the box with any type of scales.

QGraphicsItemGroup::boundingRect() not updating

I've been trying to use QGraphicsItemGroup to get the bounding rectangle of a group of QGraphicsItem*s. It appears to me that the bounding rectangle is correctly determined when I insert all of the items into the group; but if I then move items in the group, the bounding rectangle does not update to contain the moved items as I expect. I cannot find indication in the Documentation as to whether what I'm seeing is correct behavior or not; my guess is that I'm either misunderstanding how the QGraphicsItemGroup works or misusing it
An example that I've been using to test:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTransform>
#include <QGraphicsEllipseItem>
#include <QDebug>
#include <QTimer>
#include <cmath>
const double pi = 3.14;
QTransform rotation(double degrees)
{
double a = pi/180 * degrees;
double sina = sin(a);
double cosa = cos(a);
return QTransform(cosa, sina, -sina, cosa, 0, 0);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
ui->graphicsView->show();
//Shouldn't execute until after window.show() and application.exec()
//are called
QTimer::singleShot(1, this, &MainWindow::build);
}
void MainWindow::build()
{
QGraphicsEllipseItem* el1 = scene->addEllipse(-5, -5, 10, 10);
scene->addLine(0, 0, 0, 10)->setParentItem(el1);
QGraphicsEllipseItem* el2 = scene->addEllipse(-5, -5, 10, 10);
scene->addLine(0, 0, 0, 10)->setParentItem(el2);
QGraphicsEllipseItem* el3 = scene->addEllipse(-5, -5, 10, 10);
scene->addLine(0, 0, 0, 10)->setParentItem(el3);
QGraphicsEllipseItem* el4 = scene->addEllipse(-5, -5, 10, 10);
scene->addLine(0, 0, 0, 10)->setParentItem(el4);
QGraphicsItemGroup* group = new QGraphicsItemGroup;
group->addToGroup(el1);
group->addToGroup(el2);
group->addToGroup(el3);
group->addToGroup(el4);
scene->addItem(group);
scene->addRect(group->boundingRect());
QTransform translate2(1, 0, 0, 1, 10, 10);
QTransform t2 = /*rotation(45) **/ translate2;
el2->setTransform(t2);
QTransform translate3(1, 0, 0, 1, 20, 20);
QTransform t3 = /*rotation(-45) **/ translate3 * t2;
el3->setTransform(t3);
QTransform translate4(1, 0, 0, 1, 20, -20);
QTransform t4 = translate4 * t3;
el4->setTransform(t4);
qDebug() << t4.dx() << t4.dy() << atan2(t4.m12(), t4.m22())*180/pi;
QTransform t4i = t4.inverted();
qDebug() << t4i.dx() << t4i.dy() << atan2(t4i.m12(), t4i.m22())*180/pi;
scene->addRect(group->boundingRect());
}
MainWindow::~MainWindow()
{
delete ui;
}
The final scene displayed looks like this
Actual outcome
But, I was expecting something like this, with a small box from the first boundingRect, and a larger one for the second
Expected outcome
Am I misunderstanding how the QGraphicsItemGroup works, or am I using it incorrectly?
Qt Version: 5.10
OS: Ubuntu 16.04
Compiler GCC 5.4
The boundingrect is only updated at additem. Therefore the method childrenBoundingRect() must be used instead of boundingRect().
In a separate subclass of QGraphicsItemGroup say MyQGraphicsItemGroup we can overload the method virtual QRectF boundingRect() const override so that childrenBoundingRect() is called.
QRectF MyQGraphicsItemGroup::boundingRect() const
{
// must be overloaded, otherwise the boundingrect will only be actualized on
// additem is actualized. This leads to the fact that the boundingrect
// will not close around the word items after e.g., moving them.
return childrenBoundingRect();
}
The QGraphicsItemGroup documentation doesn't seem to mention this, but it only recalculates the boundingRect for a QGraphicsItemGroup after the view and QGraphicsScene is shown.
Adding the items afterwards
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
QGraphicsView mainView(&scene);
scene.setSceneRect(0, 0, 800, 800);
QGraphicsEllipseItem* el1 = scene.addEllipse(-5, -5, 10, 10);
scene.addLine(0, 0, 0, 10)->setParentItem(el1);
QGraphicsEllipseItem* el2 = scene.addEllipse(-5, -5, 10, 10);
scene.addLine(0, 0, 0, 10)->setParentItem(el2);
QGraphicsEllipseItem* el3 = scene.addEllipse(-5, -5, 10, 10);
scene.addLine(0, 0, 0, 10)->setParentItem(el3);
QGraphicsEllipseItem* el4 = scene.addEllipse(-5, -5, 10, 10);
scene.addLine(0, 0, 0, 10)->setParentItem(el4);
QGraphicsItemGroup* group = new QGraphicsItemGroup;
scene.addItem(group);
QTransform translate2(1, 0, 0, 1, 10, 10);
QTransform t2 = /*rotation(45) **/ translate2;
el2->setTransform(t2);
QTransform translate3(1, 0, 0, 1, 20, 20);
QTransform t3 = /*rotation(-45) **/ translate3 * t2;
el3->setTransform(t3);
QTransform translate4(1, 0, 0, 1, 20, -20);
QTransform t4 = translate4 * t3;
el4->setTransform(t4);
mainView.show();
group->addToGroup(el1);
group->addToGroup(el2);
group->addToGroup(el3);
group->addToGroup(el4);
scene.addRect(group->boundingRect());
qDebug() << group->sceneBoundingRect() << endl << group->boundingRect();
scene.addRect(group->sceneBoundingRect());
return a.exec();
}
Results in the bounding rect of all members of the group

QtWidget Disable Margin for overlay widget

My situation: I have a grid layout with n*n widgets inside. Additionally I place an overlay widget in the grid with position 0,0 and span n,n.
Evertyhing fine with this, but there is a weird margin and I don't know what causes it...
Has anyone an idea how i can prevent this? I think I'm missing something trivial...
SudokuFieldWidget::SudokuFieldWidget(QWidget *parent) : QFrame(parent)
{
...
m_layout = new QGridLayout( this );
m_layout->setSpacing( 0 );
m_layout->setMargin( 1 );
this->initCells( true );
this->setLayout( m_layout );
m_markerOverlay = new SudokuMarkerOverlayWidget( this );
m_layout->addWidget( m_markerOverlay, 0, 0, m_fieldSize, m_fieldSize );
}
SudokuMarkerOverlayWidget::SudokuMarkerOverlayWidget(QWidget* parent) : QWidget(parent)
{
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TransparentForMouseEvents);
...
}
void SudokuMarkerOverlayWidget::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.fillRect( rect(), QColor( 255, 0, 0, 128 ) );
}
Had an error in my paint-Routine for SudokuFieldWidget which caused this misbehaviour... m_markerOverlay->setGeometry( this->geometry() );

Overloading of qwt setPen does not work

I wanted to compile the following code:
#include <QApplication>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_grid.h>
#include <qwt_symbol.h>
#include <qwt_legend.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QwtPlot plot;
plot.setTitle( "Plot Demo" );
plot.setCanvasBackground( Qt::white );
plot.setAxisScale( QwtPlot::yLeft, 0.0, 10.0);
plot.insertLegend( new QwtLegend() );
QwtPlotGrid *grid = new QwtPlotGrid();
grid->attach( &plot );
QwtPlotCurve *curve = new QwtPlotCurve();
curve->setTitle( "Pixel Count" );
curve->setPen( Qt::blue, 4 ),
curve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
QwtSymbol *symbol = new QwtSymbol( QwtSymbol::Ellipse,
QBrush( Qt::yellow ), QPen( Qt::red, 2 ), QSize( 8, 8 ) );
curve->setSymbol( symbol );
QPolygonF points;
points << QPointF( 0.0, 4.4 ) << QPointF( 1.0, 3.0 )
<< QPointF( 2.0, 4.5 ) << QPointF( 3.0, 6.8 )
<< QPointF( 4.0, 7.9 ) << QPointF( 5.0, 7.1 );
curve->setSamples( points );
curve->attach( &plot );
plot.resize( 600, 400 );
plot.show();
return a.exec();
}
But I get the error "No matching function to call for QwtPlotCurve::setPen(...). Candidate is "QwtPlotCurve::setPen(const QPen&)". But according to the documentation (http://qwt.sourceforge.net/class_qwt_plot_curve.html#ae00bd073a2bcf7c3c810d70af1f86750) this function should be overloaded, on the one hand as setPen(const QPen&), but on the other hand as setPen(const QColor & color, qreal width = 0.0, Qt::PenStyle style Qt::SolidLine), but my QT compiler does not recognize this second overloading variable. Why? I already entered the necessary variables into the *.pro-file.
Edit: I could solve this problem by creating a QPen and added the necessary features manually, but this should only be a temporary fix...

GTK y-axis padded label doesn't vertically ALIGN_BOTTOM?

I'm trying to align a label so that there is space on top and not on the bottom. What I want is about 30 between label1 and label2 but not between label2 and label3. I set label2 y padding to 30 and then on label2 y Gtk::ALIGN_BOTTOM, but it doesn't seem to work. Instead what I end up with is what looks like in the screenshot to be 30 on the top and 30 on the bottom of label2. I know there are ways around this but I want to know what is wrong with this code? I can't figure it out. I tried changing the pack options but that didn't work.
Here is the screenshot and here is the sample code:
int main( int argc, char *argv[] )
{
Gtk::Main kit( argc, argv );
Gtk::Window window;
window.set_default_size( 400, 400 );
Gtk::Label label1( "This is the first label." );
Gtk::Label label2( "This is the second label." );
Gtk::Label label3( "This is the third label." );
label2.set_padding( 0, 30 );
label2.set_alignment( Gtk::ALIGN_RIGHT, Gtk::ALIGN_BOTTOM );
Gtk::VBox vbox;
vbox.pack_start( label1, false, false, 0 );
vbox.pack_start( label2, false, false, 0 );
vbox.pack_start( label3, false, false, 0 );
window.add( vbox );
window.show_all_children();
Gtk::Main::run( window );
return 0;
}
Thanks
You'll need something like this (untested):
Gtk::Alignment alignment( 0.0, 1.0, 0.0, 0.0 );
alignment.set_padding( 30, 0, 0, 0 );
alignment.add( label2 );
The problem is that label.set_alignment() doesn't align within the padding, only within leftover space allocated to the widget.