2012-05-16 2 views
1

Я пытаюсь создать приложение, которое отображает PDF-файл, используя PyQt4 и python-poppler-qt4.Каков наиболее эффективный способ отображения нескольких растровых изображений в области прокрутки?

До сих пор мне удалось отобразить весь документ, загрузив pixmaps, сгенерированные с помощью Poppler, установленные в QLabel и добавленные в QFrame. QFrame отображается в QScrollArea.

Он выглядит довольно неплохо, пока не выполняется масштабирование, которое выполняется путем регенерации pixmaps снова и снова с увеличенным разрешением. Этот процесс требует, чтобы весь документ был отображен в pixmaps, что, очевидно, требует времени и результатов в нежелательном лагере.

Логика хочет, чтобы мне отображались изображения только тех страниц, которые я вижу (это звучит как квантовая физика). У меня есть два варианта:

  1. создавать пустые страницы с QLabels и загружать изображение на них, когда они становятся видимыми в области прокрутки;
  2. создайте только одну страницу и добавьте или удалите прецедент или последующие страницы непосредственно перед ее отображением.

Я не уверен, что нахожусь на правильном пути или есть альтернатива.

Первый вариант кажется более выполнимым, поскольку видимость пустой страницы определяет, когда нужно загрузить pixmap (хотя я не знаю, как удалить эту карту pixmap, когда страница скрыта). Тем не менее я не уверен, что масштабирование будет быстрее таким образом, поскольку документ, скажем, 600 страниц, должен быть восстановлен, хотя и с пустыми страницами.

Второй вариант должен определенно улучшить масштабирование, так как при масштабировании необходимо будет восстановить от 1 до 4 страниц за раз. Однако в этом втором случае я не уверен, как инициировать построение страниц.

Что вы предложите?

ответ

1

Я выработанный ответ, используя вариант 1 вопрос:

def moveEvent(self, event): 
    self.checkVisibility() 
    event.ignore() 

def resizeEvent(self, event): 
    self.checkVisibility() 
    event.ignore() 

def checkVisibility(self): 
    print "Checking visibility" 
    for page in self.getPages(): 
     if not page.visibleRegion().isEmpty(): 
      if page.was_visible: 
       pass 
      else: 
       print page.page_number, "became visible" 
       page.was_visible = True 
       self.applyImageToPage(page) 
     else: 
      if page.was_visible: 
       print page.page_number, "became invisible" 
       page.was_visible = False 
      else: 
       pass 
def applyImageToPage(self, page): 
    print "applying image to page", page.page_number 
    source = self.getSourcePage(self.getPageNumber(page)) 
    scale = self.display.scale 
     # this is where the error occurs 
    image = source.renderToImage(72 * scale, 72 * scale) 
    pixmap = QtGui.QPixmap.fromImage(image) 
    page.setPixmap(pixmap) 
+0

Вариант второй менее эффективен, так как он требует перезагрузки одинаковых растровых изображений. Приведенный выше код должен быть улучшен при использовании потока вместо этого, чтобы избежать задержек при прокрутке. – Benjamin

+0

PS: потоки в Qt4 не работают хорошо при выполнении графики. Поток создает искаженные изображения или приводит к сбою приложения. Возможно, я не справился с этим достаточно хорошо. В любом случае прокрутка задержки в основном является результатом большого DPI. Следовательно, если изображение повторно загружается в соответствии с уровнем масштабирования, тогда количество обрабатываемых данных на видимую область достаточно светлое, чтобы не допускать плавной прокрутки. – Benjamin

1

не было бы просто забыть QLabel с и непосредственно рисовать изображение:

from PyQt4.QtGui import * 
import sys 

app = QApplication(sys.argv) 

class Test(QWidget): 

    def __init__(self): 
     super(Test, self).__init__() 
     self.painter = QPainter() 
     # placeholder for the real stuff to draw 
     self.image = QImage("/tmp/test.jpg") 

    def paintEvent(self, evt): 
     rect = evt.rect() 
     evt.accept() 
     print rect 
     self.painter.begin(self) 
     zoomedImage = self.image # ... calculate this for your images 
     sourceRect = rect   # ... caluclate this ... 
     # draw it directly 
     self.painter.drawImage(rect, self.image, sourceRect) 
     self.painter.end() 


t = Test() 
t.setGeometry(0,0,600,800) 

s = QScrollArea() 
s.setWidget(t) 

s.setGeometry(0,0,300,400) 
s.show() 
app.exec_() 
+0

Спасибо , Я видел код с использованием Painter() раньше, и он продолжает избегать моего понимания. Поэтому, пожалуйста, медведь со мной. Художник рисует своего родителя, Test()? С несколькими страницами каждый из них должен быть похожим на Test() виджет, установленным вертикально на QFrame(), который установлен в QScrollArea? Рисует ли paintEvent() каждый раз, когда появляется страница или часть страницы? Я понимаю, что вы предлагаете правильно, если я говорю, что он постепенно рисует изображения по мере их появления? – Benjamin

+0

, который компонент, который рисует художник, устанавливается в вызове метода 'begin', поэтому в этом случае это' QWidget' ('self'). 'paintEvent' вызывается каждый раз, когда компонент должен быть перекрашен, а' evt.rect() 'дает вам область, которая должна быть переиздана, поэтому вам нужно только нарисовать видимую часть. я не знаю, как должен выглядеть ваш макет, поэтому я не могу сказать вам, как это сделать. – mata

+0

Это работает, когда одна страница (которая является самонастраивающейся QWidget, как вы указали выше) является основным виджетами QScrollArea. Если я добавлю много таких страниц на QFrame и QVBoxLayout, тогда paintEvent страниц не запускается, и я не вижу ничего. Как это возможно? – Benjamin