[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    Need Qt painting internals help with my KPixmapSequenceOverlayPainter
From:       Sebastian =?iso-8859-1?q?Tr=FCg?= <trueg () kde ! org>
Date:       2009-07-22 8:28:46
Message-ID: 200907221028.46202.trueg () kde ! org
[Download RAW message or body]

Hello guys,

Gwenview has a nice spinner when loading an image. I wanted to reuse and, 
thus, molded the code used to paint it into two classes:

KPixmapSequence:
A very simple container for a series of pixmaps extracted from a pixmap like 
progress-working.png.

KPixmapSequenceOverlayPainter:
Installs an event filter on any widget and paints a sequence at the configured 
position.

It works very nicely on "normal" widgets. It. however, fails on listviews. If 
installed on the view itself or the viewport, the content will not be painted 
anymore. I suspect it has something to do with the view painting directly on 
the viewport. But I was not able to find the problem and would appreciate any 
input.

The interesting method is KPixmapSequenceOverlayPainter::eventFilter.

Thanks a lot,
Sebastian

["kpixmapsequenceoverlaypainter.cpp" (text/x-c++src)]

/*
  Copyright 2009 Sebastian Trueg <trueg@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include "kpixmapsequenceoverlaypainter.h"
#include "kpixmapsequence.h"

#include <QtGui/QWidget>
#include <QtCore/QPoint>
#include <QtGui/QPainter>
#include <QtCore/QTimer>
#include <QtCore/QEvent>

#include <KIconLoader>
#include <KDebug>


class KPixmapSequenceOverlayPainter::Private
{
public:
    void _k_timeout();
    void paintFrame();

    KPixmapSequence m_sequence;
    QWidget* m_widget;
    Qt::Alignment m_alignment;
    QPoint m_offset;

    QTimer m_timer;
    int m_counter;

    KPixmapSequenceOverlayPainter* q;
};


void KPixmapSequenceOverlayPainter::Private::_k_timeout()
{
    ++m_counter;
    m_counter %= m_sequence.frameCount();
    m_widget->update();
}


void KPixmapSequenceOverlayPainter::Private::paintFrame()
{
    QPainter p( m_widget );

    QPoint pos;
    if ( m_alignment & Qt::AlignHCenter )
        pos.setX( ( m_widget->width() - m_sequence.frameSize().width() ) / 2 );
    else if ( m_alignment & Qt::AlignRight )
        pos.setX( m_widget->contentsRect().right() - m_sequence.frameSize().width() );

    if ( m_alignment & Qt::AlignVCenter )
        pos.setY( ( m_widget->height() - m_sequence.frameSize().height() ) / 2 );
    else if ( m_alignment & Qt::AlignBottom )
        pos.setY( m_widget->contentsRect().bottom() - m_sequence.frameSize().height() );

    pos += m_offset;

    p.drawPixmap( pos, m_sequence.frameAt( m_counter ) );
}


KPixmapSequenceOverlayPainter::KPixmapSequenceOverlayPainter( QObject* parent )
    : QObject( parent ),
      d( new Private )
{
    d->q = this;
    d->m_widget = 0;
    d->m_alignment = Qt::AlignCenter;
    setInterval( 200 );
    d->m_sequence.load( KIconLoader::global()->iconPath("process-working", -22 ) );
    connect( &d->m_timer, SIGNAL( timeout() ), this, SLOT( _k_timeout() ) );
}


KPixmapSequenceOverlayPainter::~KPixmapSequenceOverlayPainter()
{
    stop();
    delete d;
}


KPixmapSequence KPixmapSequenceOverlayPainter::sequence() const
{
    return d->m_sequence;
}


int KPixmapSequenceOverlayPainter::interval() const
{
    return d->m_timer.interval();
}


void KPixmapSequenceOverlayPainter::setSequence( const KPixmapSequence& seq )
{
    d->m_sequence = seq;
}


void KPixmapSequenceOverlayPainter::setInterval( int msecs )
{
    d->m_timer.setInterval( msecs );
}


void KPixmapSequenceOverlayPainter::setWidget( QWidget* w )
{
    stop();
    d->m_widget = w;
}


void KPixmapSequenceOverlayPainter::setPosition( Qt::Alignment align, const QPoint& offset )
{
    d->m_alignment = align;
    d->m_offset = offset;
}


void KPixmapSequenceOverlayPainter::start()
{
    if ( d->m_widget ) {
        stop();

        d->m_counter = 0;
        d->m_widget->installEventFilter( this );
        d->m_timer.start();
        d->m_widget->update();
    }
}


void KPixmapSequenceOverlayPainter::stop()
{
    d->m_timer.stop();
    if ( d->m_widget ) {
        d->m_widget->removeEventFilter( this );
        d->m_widget->update();
    }
}


bool KPixmapSequenceOverlayPainter::eventFilter( QObject* obj, QEvent* event )
{
    if ( obj == d->m_widget && event->type() == QEvent::Paint ) {
        obj->event( event );
        d->paintFrame();
        return true;
    }

    return false;
}

#include "kpixmapsequenceoverlaypainter.moc"

["kpixmapsequence.cpp" (text/x-c++src)]

/*
  Copyright 2008 Aurélien Gâteau <agateau@kde.org>
  Copyright 2009 Sebastian Trueg <trueg@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include "kpixmapsequence.h"

#include <QtGui/QPixmap>
#include <QtGui/QPainter>
#include <QtCore/QVector>

#include <kdebug.h>


class KPixmapSequence::Private : public QSharedData
{
public:
	QVector<QPixmap> mFrames;
};


KPixmapSequence::KPixmapSequence()
    : d(new Private)
{
}


KPixmapSequence::KPixmapSequence( const KPixmapSequence& other )
{
    d = other.d;
}


KPixmapSequence::~KPixmapSequence()
{
}


KPixmapSequence& KPixmapSequence::operator=( const KPixmapSequence& other )
{
    d = other.d;
    return *this;
}


bool KPixmapSequence::isValid() const
{
    return !isEmpty();
}


bool KPixmapSequence::isEmpty() const
{
    return d->mFrames.isEmpty();
}


bool KPixmapSequence::load(const QString& path)
{
	QPixmap bigPixmap;
	if (!bigPixmap.load(path)) {
		kWarning() << "Could not load animation image from" << path;
		return false;
	}
    else {
        return load( bigPixmap );
    }
}


bool KPixmapSequence::load(const QPixmap& bigPixmap)
{
	d->mFrames.resize(bigPixmap.height() / bigPixmap.width());
	const int size = bigPixmap.width();

	for(int pos=0; pos < d->mFrames.size(); ++pos) {
		QPixmap pix = QPixmap(size, size);
		pix.fill(Qt::transparent);
		QPainter painter(&pix);
		painter.drawPixmap(QPoint(0, 0), bigPixmap, QRect(0, pos * size, size, size));
		d->mFrames[pos] = pix;
	}
	return true;
}


QSize KPixmapSequence::frameSize() const
{
	if (d->mFrames.size() == 0) {
		kWarning() << "No frame loaded";
		return QSize();
	}
	return d->mFrames[0].size();
}


int KPixmapSequence::frameCount() const
{
	return d->mFrames.size();
}


QPixmap KPixmapSequence::frameAt(int index) const
{
	return d->mFrames.at( index % frameCount() );
}


KPixmapSequence KPixmapSequence::loadFromPath( const QString& path )
{
    KPixmapSequence s;
    s.load( path );
    return s;
}


KPixmapSequence KPixmapSequence::loadFromPixmap( const QPixmap& pix )
{
    KPixmapSequence s;
    s.load( pix );
    return s;
}

["kpixmapsequenceoverlaypainter.h" (text/x-chdr)]

/*
  Copyright 2009 Sebastian Trueg <trueg@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#ifndef _K_PIXMAPSEQUENCE_OVERLAY_PAINTER_H_
#define _K_PIXMAPSEQUENCE_OVERLAY_PAINTER_H_

#include <QtCore/QObject>
#include <QtCore/QPoint>

#include "kdeui_export.h"

class KPixmapSequence;
class QWidget;
class QEvent;

/**
 * \class KPixmapSequenceOverlayPainter kpixmapsequenceoverlaypainter.h KPixmapSequenceOverlayPainter
 *
 * \brief Paints a KPixmapSequence on top of any widget at any position.
 *
 * The KPixmapSequenceOverlayPainter paints an overlay on top of an arbitrary QWidget
 * using a KPixmapSequence. This is typically used for spinners indicating that a process
 * is not finished yet.
 *
 * \author Sebastian Trueg <trueg@kde.org>
 */
class KDEUI_EXPORT KPixmapSequenceOverlayPainter : public QObject
{
    Q_OBJECT

public:
    /**
     * Constructor
     */
    KPixmapSequenceOverlayPainter( QObject* parent = 0 );

    /**
     * Destructor
     */
    ~KPixmapSequenceOverlayPainter();

    /**
     * The sequenece used to draw the overlay.
     *
     * \sa setSequence
     */
    KPixmapSequence sequence() const;

    /**
     * The interval between frames.
     *
     * \sa setInterval
     */
    int interval() const;

public Q_SLOTS:
    /**
     * Set the sequence to be used. By default the KDE busy sequence is used.
     */
    void setSequence( const KPixmapSequence& seq );

    /**
     * Set the interval between frames. The default is 200.
     */
    void setInterval( int msecs );

    /**
     * Set the widget to draw the overlay on.
     */
    void setWidget( QWidget* w );

    /**
     * Set the position where to draw the overlay.
     *
     * \param align alignment of the overlay. Qt::AlignJustify does not make sense here.
     * Defaults to Qt::Center.
     * \param offset An optional offset which allows an absolute placement.
     */
    void setPosition( Qt::Alignment align, const QPoint& offset = QPoint() );

    /**
     * Start drawing the sequence.
     *
     * The overlay will be drawn until a call to stop()
     */
    void start();

    /**
     * Stop drawing the overlay.
     */
    void stop();

private:
    bool eventFilter( QObject* obj, QEvent* event );

    class Private;
    Private* const d;

    Q_PRIVATE_SLOT( d, void _k_timeout() )
};

#endif

["kpixmapsequence.h" (text/x-chdr)]

/*
  Copyright 2008 Aurélien Gâteau <agateau@kde.org>
  Copyright 2009 Sebastian Trueg <trueg@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#ifndef _K_PIXMAPSEQUENCE_H_
#define _K_PIXMAPSEQUENCE_H_

#include <QtCore/QSharedDataPointer>

#include "kdeui_export.h"

class QPixmap;
class QSize;

/**
 * \class KPixmapSequence kpixmapsequence.h KPixmapSequence
 *
 * \brief Loads and gives access to the frames of a typical multi-row pixmap
 * as often used for spinners.
 *
 * KPixmapSequence is implicitly shared. Copying is fast.
 *
 * Once typically uses the static methods loadFromPath and loadFromPixmap
 * to create an instance of KPixmapSequence.
 *
 * \author Aurélien Gâteau <agateau@kde.org><br/>Sebastian Trueg <trueg@kde.org>
 */
class KDEUI_EXPORT KPixmapSequence
{
public:
    /**
     * Create an empty sequence
     */
	KPixmapSequence();

    /**
     * Copy constructor
     */
	KPixmapSequence( const KPixmapSequence& other );

    /**
     * Destructor
     */
	~KPixmapSequence();

    /**
     * Create a copy of \p other. The data is implicitly shared.
     */
    KPixmapSequence& operator=( const KPixmapSequence& other );

    /**
     * \return \p true if a sequence was loaded successfully.
     *
     * \sa isEmpty
     */
    bool isValid() const;

    /**
     * \return \p true if no sequence was loaded successfully.
     *
     * \sa isValid
     */
    bool isEmpty() const;

    /**
     * Load a pixmap sequence from \p path.
     *
     * \return \p true if loading was sucessful, \p false otherwise.
     */
	bool load( const QString& path );

    /**
     * Load a pixmap sequence from \p pixmap which contains a set of
     * frames in one column.
     *
     * \return \p true if loading was sucessful, \p false otherwise.
     */
    bool load( const QPixmap& pixmap );

    /**
     * \return The size of an individual frame in the sequence.
     * Be aware that frames are always taken to be squared.
     */
	QSize frameSize() const;

    /**
     * The number of frames in this sequence.
     */
	int frameCount() const;

    /**
     * Retrieve the frame at \p index.
     *
     * \param index The index of the frame in question starting at 0.
     * \p index greater than frameCount() is perfectly valid. The
     * sequence will simply start over.
     */
	QPixmap frameAt( int index ) const;

    static KPixmapSequence loadFromPath( const QString& path );
    static KPixmapSequence loadFromPixmap( const QPixmap& path );

private:
    class Private;
	QSharedDataPointer<Private> d;
};

#endif


>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic