# 11.2. Rollbare Ansichten

In diesem Abschnitt werden wir eine Funktionalität implementieren, die meistens zum Kreuz für die Entwickler wird - wenn Sie nicht auf bereits implementierte Widgets zurückgreifen können, die das Rollen schon mitbringen. Was bedeutet Rollen? In unserem Kontext beginnt das Problem damit, das wir ein Bild öffnen wollen, das viel größer als der darstellbare Bereich ist. Beginnend von der oberen, linken Ecke, wird der Rest des Bildes aus der Sicht des Benutzers ausgeschnitten. Eine Rollansicht ist ein Widget, das auf der rechten und unteren Seite Rollbalken zur Verfügung stellt, mit deren Hilfe der Benutzer den Inhalt des Fensters verschieben kann. Tatsächlich wird das Dokument in seiner ganzen Größe gezeigt, aber die Ansicht kann innerhalb des Dokuments bewegt werden, sodaß jeder Teil mit Hilfe der Scrollbars angezeigt werden kann. Glücklicherweise gibt es in Qt die Klasse `QScrollView`,die selber von `QWidget` abgeleitet ist und die gleiche Grundfunktionalität wie ein gewöhnliches Widget bietet, jedoch den Inhalt der Ansicht bei der Verwendung von Scrollbars verwaltet - mit der zusätzlichen Option, daß der Programmierer entweder einfach nur eine Instanz von `QScrollView` verwendet, die zu verwaltenden Kindfenster mit der Rollansicht als Eltern erstellt und sie mit `addChild()` der Rollansicht hinzufügt, oder eine Ansicht von `QScrollView` ableitet und dann, statt direkt in das Widget, in den Viewport zeichnet, der ein definierter Bereich innerhalb der Rollansicht ist. Der Unterschied hier ist, daß `QScrollView` einen Satz von Ereignisbehandlungsroutinen, ähnlich denen von `QWidget`, extra für den Viewport bereitstellt. Das was also vorher `mousePressEvent()` in unserer Ansicht war, ist jetzt ein viewportMousePressEvent, ein `paintEvent()` wird zu einem viewportPaintEvent usw. . Die zweite der genannten Möglichkeiten passt auf unsere Anforderungen, wir werden also folgendene Modifikationen vornehmen, um KScribbleView zu einem rollbaren Widget zu machen:

- Zunächst müssen wir das Dokument der Größe seines Inhalts anpassen. Dies kann erreicht werden, indem wir uns die Größe des geöffneten Bildes holen, für ein neues Bild müssen wir eine Standardgröße definieren. In anderen Zeichenanwendungen kann diese Größe meistens durch ein Kommando des Benutzerinterfaces, z.B. in einem Dialog, der nach der neuen Höhe und Breite fragt, sowie einer Methode zur Anpassung des Bildes an diese Werte, geändert werden.

- Ändern der Elternklasse für KScribbleView von `QWidget` nach `QScrollView`.

- Umbenennen der virtuellen Methoden in die entsprechenden Viewportmethoden aus `QScrollView`.

- Adaptieren der virtuellen Event Handler, sodaß sie die Geometrie des Viewports beeinflussen. Das bedeutet, daß die alte Implementation auf die Geometrie von `QWidget` vertraut, die in der linken, oberen Ecke eines Widgets beginnt. Wenn die Ansicht gerollt wird und diese Ecke ist nicht sichtbar, müssen wir dafür sorgen, daß die von `QWidget` gelieferten Positionen in Viewportkoordinaten übersetzt werden.

## 11.2.1. Größe des Dokumentinhalts verändern

Wie bereits erwähnt, müssen wir sowohl die Größe eines Dokuments ändern, als auch diese Größe initialisieren, und wir müssen eine Methode bereitstellen, die diese Größe für die Ansichten holt. Dazu fügen wir die Variable `QSize size` sowie die Methode `docSize()` in `KScribbleDoc` ein:

       1 kscribbledoc.h:
       2
       3 #include <qsize.h>
       4
       5 ...
       6 public:
       7   const QSize docSize(){ return size;};
       8
       9 private:
      10   QSize size;

Jetzt müssen wir alle Methoden, die Dokumentinhalte öffnen oder initialisieren, modifizieren.Dies sind `newDocument()` und `openDocument()`:

       1   bool KScribbleDoc::newDocument()
       2   {
       3     /////////////////////////////////////////////////
       4     // TODO: Add your document initialization code here
       5 ->  size=QSize(300,200 );
       6    	pen=QPen( Qt::black, 3 );
       7 ->  buffer.resize(size);
       8 ->  buffer.fill( Qt::white );
       9     /////////////////////////////////////////////////
      10     modified=false;
      11     return true;
      12   }
      13
      14   bool KScribbleDoc::openDocument(const QString &&;filename, const char *format /*=0*/)
      15   {
      16
      17   	QFile f( filename );
      18   //	if ( !f.open( IO_ReadOnly ) )
      19   //		return false;
      20     /////////////////////////////////////////////////
      21     // TODO: Add your document opening code here
      22   	if(!buffer.load( filename, format ))
      23   		return false;
      24 ->  size=buffer.size();
      25     /////////////////////////////////////////////////
      26   //	f.close();
      27
      28     modified=false;
      29     m_filename=filename;
      30   	m_title=QFileInfo(f).fileName();
      31     return true;
      32   }

In `newDocument()` initialisieren wir die Größe mit Standardwerten von 300 Pixeln Breite und 200 Pixeln Höhe. Das ist genug für ein kleines Bild und wir könnten auch immer noch einen Dialog zur Größenänderung hinzufügen. Wenn es daran geht, das Bild zu öffnen, müssen wir die Größe auf die des Bildes setzen. Dies kann man erreichen, indem man `QPixmap::size()` aufruft, was wir bereits in `openDocument()` verwendet haben. Dann sind mit dem Setzen der Größen fertig, und wir können damit beginnen, KScribbleView zu reimplementieren und eine Rollansicht daraus zu machen.