37812
PrintPreviewの導入に成功し、プリントのプレビュー表示を  
早速出してみました。  
プレビューを表示するためのコードです。  
読んでもらえたら結構勉強になるかもしれ  
ません。  
プレビューを表示するためにどうすればい  
いのか考えあぐねていたら、ここを読んでみて  
ピンと来た気がします。毎度長文で申し訳あり  
ません。  
[Print A Text Through A Printer Using
PyQt4](http://Print%20A%20Text%20Through%20A%20Printer%20Using%20PyQt4)

```

    　　　　 printer = QtGui.QPrinter()
            printer.setDocName(self.windowTitle())
            printer.setPageSize(QtGui.QPrinter.A4)        
            printer.setOutputFormat(QtGui.QPrinter.NativeFormat)
            printer.setOrientation(QtGui.QPrinter.Portrait)
            printer.setResolution(QtGui.QPrinter.HighResolution)
            printer.setCopyCount(self.printer_pagecountspinbox.value())
            #ここで、ドキュメントに設定してある余白を、プリンターにもセットしてしまうと、二重に計上されるバグ？そのため、コメント化を行って、回避。
    #        printer.setPageMargins(self.main_menubar_layout_document_left_margin_spinbox.value(),self.main_menubar_layout_document_top_margin_spinbox.value(),\
    #                                                self.main_menubar_layout_document_right_margin_spinbox.value(),self.main_menubar_layout_document_bottom_margin_spinbox.value(),\
    #                                                QtGui.QPrinter.Millimeter)
            if self.main_view.textediter.document().documentLayout().pageCount() == 1:
                #なぜか、一ページ目の白紙ドキュメントは、サイズがQtCore.QSizeF(797,-1)となり、正常に1ページ目を表示してくれないため、再認識修正（コンストラクタで本当はやってるんだけど反映されない。ここは、B5やB4等を増やしたときに拡張する予定）
                self.main_view.textediter.document().setPageSize(QtCore.QSizeF(797,1123))
            self.print_preview_widget = QtGui.QPrintPreviewDialog(printer,self) 
                #showMaximized()を使い、全体表示をすれば、何も映らなくなる。なぜかわからないバグ。            
            self.print_preview_widget.setGeometry(150,150,1500,1500)
                #ここがミソ。コールしない。コールすると打ち出しを始めてしまったりする　C++と表記が異なる点。QPrinter*　つまり、ポインタを渡せという事。純粋Pythonerには少しハードルが高かった。
                #今までもコールでprinterをセットしていたかもしれない。忘れたころにまたやってしまう失敗。
                #残念ながら、self.main_view.textediter.document().print_とした場合、Failed to connect signal　エラーが発生、これでもよくないかと考えてしまう。
            self.print_preview_widget.paintRequested.connect(self.main_view.textediter.print_)
            self.print_preview_widget.exec_()  
    
```

**具体的な問題**  
既にページネーションが行われているので、ページ間の  
余白は意識することなくQTextEditの編集中の状態をその  
まま、プレビューに表示できるようになりました。  
もちろんプリントもできます。  
しかし、`QTextObjectInterface`によるカスタムオブジ  
ェクトが、正確に表示されません。  
`QTextObjectInterface`内のpainterメソッドは、下記の  
コードかこちらを参照  
[QTextObjectInterfaceの導入方法について](https://ja.stackoverflow.com/questions/37162/qtextobjectinterface-
pyside%E3%81%A7%E3%81%AE%E5%B0%8E%E5%85%A5%E6%96%B9%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)  
ちょうどカスタムオブジェクトが描かれているべきところに、  
灰のつぶのような小さな点が見えたので、もしやと思い、拡  
大ボタンを押して、1500%くらいまで 拡大してみました。  
すると、豆粒から見ても豆粒のような、灰カスのような文字が、  
大きさはともかくとして、正確に表示されていました。  
**空白であるにせよ、そこに文字が入り込むだけのスペース  
が空いています。その空白の左はじに、灰粕のように、黒い粉  
がついています。painterのフォントサイズだけ1以下にされて  
しまったような外観です。**  
つまり、QTextEdit中には通常の表示がなされているはずのカス  
タム オブジェクトが、プレビュー画面で表示したときは、どん  
なにFontをいじっても、蟻よりも小さくなっています。  
もちろん、そのままプリントしても、その通りの文字でした。  
さすがプレビューとは言えない状況でした。  
私のエディタは、Wordソフトのように、ページネーションが行わ  
れているので、`QTextDocument or QTextEdit.print_()`を  
利用すれば、そのまま表示してくれます。  
私は、あくまでもこの方法でプリントしたいと思っています。  
[便利なプリントメソッド～ページネーション時にはこれ。](https://pyside.github.io/docs/pyside/PySide/QtGui/QTextDocument.html#PySide.QtGui.PySide.QtGui.QTextDocument.print_)  
カスタムオブジェクトを、プリント時に改めて挿入すればよい  
とも思いましたが、一応レンダリングはなされている以上、小さ  
な黒い点＋挿入文字で、正確な表記ではなくなります。また、上  
記のメソッドを使えば、painterでごちゃごちゃ書かなくてもい  
いので、非常に楽なのです。特に`TextBlock`がページ間でまた  
がった場合の処理が不要になるので、一番楽です。  
小さいながらも、文字が載っているということは、必ず、この文  
字を正常な状態で載せる方法もあると思っています。しかしその  
手がかりが今のところ全くつかめません。  
CustomTextObjectを作れる仕組みがありながら、セーブ&ロード、  
プリントの手段については、リファレンスに載っていないのは、案  
外簡単な方法があるんじゃないかと考えています。じゃないと作っ  
てもアプリを消せばすべておじゃんになるから、絵にかいた餅もい  
いところだと思うからです。  
そして、こちらが、自分なりのルビ表示機能のコードです。実際ま  
だルビは汚いです。  

```

    class RubyTextObjectInterface(QtGui.QPyTextObject):
        def __init__(self,parent=None):
            super(RubyTextObjectInterface, self).__init__(parent=None)        
    
        def intrinsicSize(self,doc, posInDocument, format):  
            try:                     
                #ここのformatはQTextFormat
                #ここに、docを引数として通すと、後の処理で原因不明のエラーが発生　format_tc = QtGui.QTextCursor(doc)は、エラーになる。
                findblock = doc.findBlock(posInDocument)
                format_tc = QtGui.QTextCursor(findblock)
                format_tc_charFormat = format_tc.charFormat()
                format_charFormat = format.toCharFormat()
                format_charFormat.setFont(format_tc_charFormat.font())
                rubysize = format.property(4)
                offset = format.property(5)            
                size = QtCore.QSize(len(format.property(1))*format_charFormat.font().pointSize()+(len(format.property(2))-1)*rubysize,format_charFormat.font().pointSize()+rubysize+offset+2)
                return size
            except Exception as e:
                print(33,e)                        
        def drawObject(self,painter,rect,doc,posInDocument,format):
    
            try:
                #そもそものviewportを取得してみた。結果は(0,0,796,1131)
    #            print(102,painter.viewport())
    #            painter.setViewport(int(doc.rootFrame().frameFormat().leftMargin()),int(doc.rootFrame().frameFormat().topMargin()),int(doc.pageSize().width()),int(doc.pageSize().height()*doc.documentLayout().pageCount()))
                #formatのプロパティに現在位置を登録し、常に更新
                format.setProperty(3,posInDocument)            
                rubysize = format.property(4)
                offset = format.property(5)
                #ドキュメント上のテキストカーソルを取得            
                format_tc = QtGui.QTextCursor(doc)
                #拡張書式のある場所へ移動
                format_tc.setPosition(posInDocument)
                #現在カーソルがある位置のcharFormat()を取得
                format_tc_charFormat = format_tc.charFormat()
                #formatをcharFormat化
                format_charFormat = format.toCharFormat()
                #ルビに現在のカーソル位置のフォントをセット
                format_charFormat.setFont(format_tc_charFormat.font())
                #rectは親文字のための位置情報なので、rubyはその上にレンダリングさせるように微調整
                ruby_rect = QtCore.QRectF(rect.x(),rect.y()-rubysize-offset,rect.width(),rubysize+offset)
                painter.setFont(format.property(7))
                painter.drawText(rect,format.property(1))
                painter.setFont(QtGui.QFont(format.property(8).rawName(),rubysize))
                painter.drawText(ruby_rect,format.property(6),format.property(2))
    
```

ご存知の方や、こうすればどうかというお考えをお持ちの方は  
何でもいいのでお寄せください。よろしくお願いします。  
**～蛇足～**  
**カスタムテキストオブジェクトに当たっての導入必要な処理** 進捗状況  
①BoldやItalic,Underlineをダイナミックに適用する。 ×  
②fontの変更、fontsizeの変更をダイナミックに適用する。 ×  
③printoutとpreview表示を可能にする。 ×  
④save&loadを可能にする。（強引に可能にしたが、もっと楽な方法が欲しい） △  
⑤copy&pasteを可能にする。 ×  
①と②と⑤は、脳内でちょっと図が出来上がっていて、④は、もっ  
と楽な方法が欲しいです。これはまたおいおい質問していけれ  
ばいいなと思っています。  
すぐに試してみる事も可能なのですが、インターフェースの  
メソッドを、IntrinsicSizeとdrawObject以外に追加しても  
怒られませんよね？
CC BY-SA 3.0
2017-09-05T11:16:37.783
37734
2017-09-08T12:26:42.840
2017-09-07T06:14:16.690
24284
24284
question
python qt
Custom Text Objects PrintPreviewの表示について-Ruby表示コードとPreview表示コード掲載-
直接実行できるコードではないので、気づく範囲の回答になりますが、  
少なくとも`QPrinter.setResolution()`の引数を間違えているように見えます。  
このメソッドの引数は、具体的なDPIを指定することになっており、`QPrinter.HighResolution`は指定しません。`QPrinter.HighResolution`は`QPrinter`のコンストラクタで指定します。(参考:
[QPrinterの文書](https://srinikom.github.io/pyside-
docs/PySide/QtGui/QPrinter.html))  
あるいは、プレビューであれば`QPrintPreviewDialog`のコンストラクタに`QPrinter`を指定しなくても十分と思います。

一方、`QPrinter.HighResolution`を`QPrinter`に指定する場合、1200DPIとして扱われるようなので、`RubyTextObjectInterface.intrinsicSize()`や`drawObject()`内で描画物を「1200
÷ 96」倍で描画すると、プレビュー画面で見えるようになると思います。

＃「96」は`QPrinter.ScreenResolution`を指定した際のDPI。

以上、参考になれば幸いです。
CC BY-SA 3.0
2017-09-08T12:26:42.840
37812
2017-09-08T12:26:42.840
20098
37734
answer