mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-11-04 00:04:25 -05:00 
			
		
		
		
	[api] Add option for setting a line symbol to use when rendering
a QgsRubberBand
This commit is contained in:
		
							parent
							
								
									ad56216f14
								
							
						
					
					
						commit
						ccaca736c3
					
				@ -68,6 +68,7 @@ Creates a new RubberBand.
 | 
			
		||||
:param geometryType: Defines how the data should be drawn onto the screen.
 | 
			
		||||
                     :py:class:`QgsWkbTypes`.LineGeometry, :py:class:`QgsWkbTypes`.PolygonGeometry or :py:class:`QgsWkbTypes`.PointGeometry
 | 
			
		||||
%End
 | 
			
		||||
    ~QgsRubberBand();
 | 
			
		||||
 | 
			
		||||
    void setColor( const QColor &color );
 | 
			
		||||
%Docstring
 | 
			
		||||
@ -345,6 +346,36 @@ Returns the rubberband as a Geometry
 | 
			
		||||
    virtual void updatePosition();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    QgsSymbol *symbol() const;
 | 
			
		||||
%Docstring
 | 
			
		||||
Returns the symbol used for rendering the rubberband, if set.
 | 
			
		||||
 | 
			
		||||
.. seealso:: :py:func:`setSymbol`
 | 
			
		||||
 | 
			
		||||
.. versionadded:: 3.20
 | 
			
		||||
%End
 | 
			
		||||
 | 
			
		||||
    void setSymbol( QgsSymbol *symbol /Transfer/ );
 | 
			
		||||
%Docstring
 | 
			
		||||
Sets the ``symbol`` used for rendering the rubberband.
 | 
			
		||||
 | 
			
		||||
Ownership of ``symbol`` is transferred to the rubberband.
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
 | 
			
		||||
   Only line symbols are currently supported.
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
   Setting a symbol for the rubberband overrides any other appearance setting,
 | 
			
		||||
   such as the :py:func:`~QgsRubberBand.strokeColor` or :py:func:`~QgsRubberBand.width`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. seealso:: :py:func:`setSymbol`
 | 
			
		||||
 | 
			
		||||
.. versionadded:: 3.20
 | 
			
		||||
%End
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
 | 
			
		||||
    virtual void paint( QPainter *p );
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,9 @@
 | 
			
		||||
#include "qgsvectorlayer.h"
 | 
			
		||||
#include "qgsproject.h"
 | 
			
		||||
#include "qgsrectangle.h"
 | 
			
		||||
#include "qgssymbol.h"
 | 
			
		||||
#include "qgsrendercontext.h"
 | 
			
		||||
 | 
			
		||||
#include <QPainter>
 | 
			
		||||
 | 
			
		||||
QgsRubberBand::QgsRubberBand( QgsMapCanvas *mapCanvas, QgsWkbTypes::GeometryType geometryType )
 | 
			
		||||
@ -43,6 +46,8 @@ QgsRubberBand::QgsRubberBand()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QgsRubberBand::~QgsRubberBand() = default;
 | 
			
		||||
 | 
			
		||||
void QgsRubberBand::setColor( const QColor &color )
 | 
			
		||||
{
 | 
			
		||||
  setStrokeColor( color );
 | 
			
		||||
@ -455,26 +460,45 @@ void QgsRubberBand::paint( QPainter *p )
 | 
			
		||||
    shapes.append( rings );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
 | 
			
		||||
  for ( int i = 0; i < iterations; ++i )
 | 
			
		||||
  if ( QgsLineSymbol *lineSymbol = dynamic_cast< QgsLineSymbol * >( mSymbol.get() ) )
 | 
			
		||||
  {
 | 
			
		||||
    if ( i == 0 && iterations > 1 )
 | 
			
		||||
    {
 | 
			
		||||
      // first iteration with multi-pen painting, so use secondary pen
 | 
			
		||||
      mSecondaryPen.setWidth( mPen.width() + 2 );
 | 
			
		||||
      p->setBrush( Qt::NoBrush );
 | 
			
		||||
      p->setPen( mSecondaryPen );
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      // "top" layer, use primary pen/brush
 | 
			
		||||
      p->setBrush( mBrush );
 | 
			
		||||
      p->setPen( mPen );
 | 
			
		||||
    }
 | 
			
		||||
    QgsRenderContext context( QgsRenderContext::fromQPainter( p ) );
 | 
			
		||||
    context.setFlag( QgsRenderContext::Antialiasing, true );
 | 
			
		||||
 | 
			
		||||
    lineSymbol->startRender( context );
 | 
			
		||||
    for ( const QVector<QPolygonF> &shape : qgis::as_const( shapes ) )
 | 
			
		||||
    {
 | 
			
		||||
      drawShape( p, shape );
 | 
			
		||||
      for ( const QPolygonF &ring : shape )
 | 
			
		||||
      {
 | 
			
		||||
        lineSymbol->renderPolyline( ring, nullptr, context );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    lineSymbol->stopRender( context );
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
 | 
			
		||||
    for ( int i = 0; i < iterations; ++i )
 | 
			
		||||
    {
 | 
			
		||||
      if ( i == 0 && iterations > 1 )
 | 
			
		||||
      {
 | 
			
		||||
        // first iteration with multi-pen painting, so use secondary pen
 | 
			
		||||
        mSecondaryPen.setWidth( mPen.width() + 2 );
 | 
			
		||||
        p->setBrush( Qt::NoBrush );
 | 
			
		||||
        p->setPen( mSecondaryPen );
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        // "top" layer, use primary pen/brush
 | 
			
		||||
        p->setBrush( mBrush );
 | 
			
		||||
        p->setPen( mPen );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      for ( const QVector<QPolygonF> &shape : qgis::as_const( shapes ) )
 | 
			
		||||
      {
 | 
			
		||||
        drawShape( p, shape );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -630,6 +654,16 @@ void QgsRubberBand::updateRect()
 | 
			
		||||
  setRect( rect );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QgsSymbol *QgsRubberBand::symbol() const
 | 
			
		||||
{
 | 
			
		||||
  return mSymbol.get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QgsRubberBand::setSymbol( QgsSymbol *symbol )
 | 
			
		||||
{
 | 
			
		||||
  mSymbol.reset( symbol );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QgsRubberBand::updatePosition()
 | 
			
		||||
{
 | 
			
		||||
  // re-compute rectangle
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@
 | 
			
		||||
 | 
			
		||||
class QgsVectorLayer;
 | 
			
		||||
class QPaintEvent;
 | 
			
		||||
class QgsSymbol;
 | 
			
		||||
 | 
			
		||||
#ifdef SIP_RUN
 | 
			
		||||
% ModuleHeaderCode
 | 
			
		||||
@ -132,6 +133,7 @@ class GUI_EXPORT QgsRubberBand : public QgsMapCanvasItem
 | 
			
		||||
     *         QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry or QgsWkbTypes::PointGeometry
 | 
			
		||||
     */
 | 
			
		||||
    QgsRubberBand( QgsMapCanvas *mapCanvas SIP_TRANSFERTHIS, QgsWkbTypes::GeometryType geometryType = QgsWkbTypes::LineGeometry );
 | 
			
		||||
    ~QgsRubberBand() override;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the color for the rubberband.
 | 
			
		||||
@ -385,6 +387,29 @@ class GUI_EXPORT QgsRubberBand : public QgsMapCanvasItem
 | 
			
		||||
 | 
			
		||||
    void updatePosition() override;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the symbol used for rendering the rubberband, if set.
 | 
			
		||||
     *
 | 
			
		||||
     * \see setSymbol()
 | 
			
		||||
     * \since QGIS 3.20
 | 
			
		||||
     */
 | 
			
		||||
    QgsSymbol *symbol() const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the \a symbol used for rendering the rubberband.
 | 
			
		||||
     *
 | 
			
		||||
     * Ownership of \a symbol is transferred to the rubberband.
 | 
			
		||||
     *
 | 
			
		||||
     * \warning Only line symbols are currently supported.
 | 
			
		||||
     *
 | 
			
		||||
     * \note Setting a symbol for the rubberband overrides any other appearance setting,
 | 
			
		||||
     * such as the strokeColor() or width().
 | 
			
		||||
     *
 | 
			
		||||
     * \see setSymbol()
 | 
			
		||||
     * \since QGIS 3.20
 | 
			
		||||
     */
 | 
			
		||||
    void setSymbol( QgsSymbol *symbol SIP_TRANSFER );
 | 
			
		||||
 | 
			
		||||
  protected:
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -423,6 +448,8 @@ class GUI_EXPORT QgsRubberBand : public QgsMapCanvasItem
 | 
			
		||||
    std::unique_ptr<QSvgRenderer> mSvgRenderer;
 | 
			
		||||
    QPoint mSvgOffset;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr< QgsSymbol > mSymbol;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Nested lists used for multitypes
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,8 @@
 | 
			
		||||
#include <qgsvectorlayer.h>
 | 
			
		||||
#include <qgsrubberband.h>
 | 
			
		||||
#include <qgslogger.h>
 | 
			
		||||
#include "qgssymbol.h"
 | 
			
		||||
#include "qgsrenderchecker.h"
 | 
			
		||||
 | 
			
		||||
class TestQgsRubberband : public QObject
 | 
			
		||||
{
 | 
			
		||||
@ -42,12 +44,14 @@ class TestQgsRubberband : public QObject
 | 
			
		||||
    void testBoundingRect(); //test for #12392
 | 
			
		||||
    void testVisibility(); //test for 12486
 | 
			
		||||
    void testClose(); //test closing geometry
 | 
			
		||||
    void testSymbolRender();
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    QgsMapCanvas *mCanvas = nullptr;
 | 
			
		||||
    QgsVectorLayer *mPolygonLayer = nullptr;
 | 
			
		||||
    QString mTestDataDir;
 | 
			
		||||
    QgsRubberBand *mRubberband = nullptr;
 | 
			
		||||
    QString mReport;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void TestQgsRubberband::initTestCase()
 | 
			
		||||
@ -75,6 +79,7 @@ void TestQgsRubberband::initTestCase()
 | 
			
		||||
  mCanvas->hide();
 | 
			
		||||
 | 
			
		||||
  mRubberband = nullptr;
 | 
			
		||||
  mReport += QLatin1String( "<h1>Rubberband Tests</h1>\n" );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestQgsRubberband::cleanupTestCase()
 | 
			
		||||
@ -83,6 +88,15 @@ void TestQgsRubberband::cleanupTestCase()
 | 
			
		||||
  delete mPolygonLayer;
 | 
			
		||||
  delete mCanvas;
 | 
			
		||||
 | 
			
		||||
  QString myReportFile = QDir::tempPath() + "/qgistest.html";
 | 
			
		||||
  QFile myFile( myReportFile );
 | 
			
		||||
  if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
 | 
			
		||||
  {
 | 
			
		||||
    QTextStream myQTextStream( &myFile );
 | 
			
		||||
    myQTextStream << mReport;
 | 
			
		||||
    myFile.close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  QgsApplication::exitQgis();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -216,6 +230,42 @@ void TestQgsRubberband::testClose()
 | 
			
		||||
  QCOMPARE( r.partSize( 0 ), 4 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestQgsRubberband::testSymbolRender()
 | 
			
		||||
{
 | 
			
		||||
  std::unique_ptr< QgsMapCanvas > canvas = qgis::make_unique< QgsMapCanvas >();
 | 
			
		||||
  canvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
 | 
			
		||||
  canvas->setFrameStyle( 0 );
 | 
			
		||||
  canvas->resize( 600, 400 );
 | 
			
		||||
  canvas->setExtent( QgsRectangle( 10, 30, 20, 35 ) );
 | 
			
		||||
  canvas->show();
 | 
			
		||||
 | 
			
		||||
  QgsRubberBand r( canvas.get(), QgsWkbTypes::LineGeometry );
 | 
			
		||||
  r.addGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString( 12 32, 18 33)" ) ) );
 | 
			
		||||
 | 
			
		||||
  std::unique_ptr< QgsLineSymbol > lineSymbol( QgsLineSymbol::createSimple(
 | 
			
		||||
  {
 | 
			
		||||
    { QStringLiteral( "line_color" ), QStringLiteral( "#0000ff" ) },
 | 
			
		||||
    { QStringLiteral( "line_width" ), QStringLiteral( "3" )},
 | 
			
		||||
    { QStringLiteral( "capstyle" ), QStringLiteral( "round" )}
 | 
			
		||||
  } ) );
 | 
			
		||||
  r.setSymbol( lineSymbol.release() );
 | 
			
		||||
 | 
			
		||||
  QPixmap pixmap( canvas->size() );
 | 
			
		||||
  QPainter painter( &pixmap );
 | 
			
		||||
  canvas->render( &painter );
 | 
			
		||||
  painter.end();
 | 
			
		||||
  QString destFile = QDir::tempPath() + QStringLiteral( "/rubberband_line_symbol.png" );
 | 
			
		||||
  pixmap.save( destFile );
 | 
			
		||||
 | 
			
		||||
  QgsRenderChecker checker;
 | 
			
		||||
  checker.setControlPathPrefix( QStringLiteral( "rubberband" ) );
 | 
			
		||||
  checker.setControlName( QStringLiteral( "expected_line_symbol" ) );
 | 
			
		||||
  checker.setRenderedImage( destFile );
 | 
			
		||||
  bool result = checker.compareImages( QStringLiteral( "expected_line_symbol" ) );
 | 
			
		||||
  mReport += checker.report();
 | 
			
		||||
  QVERIFY( result );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QGSTEST_MAIN( TestQgsRubberband )
 | 
			
		||||
#include "testqgsrubberband.moc"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								tests/testdata/control_images/rubberband/expected_line_symbol/expected_line_symbol.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tests/testdata/control_images/rubberband/expected_line_symbol/expected_line_symbol.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 2.1 KiB  | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user