Custom Text Objects PrintPreviewの表示について-Ruby表示コードとPreview表示コード掲載-
PrintPreviewの導入に成功し、プリントのプレビュー表示を
早速出してみました。
プレビューを表示するためのコードです。
読んでもらえたら結構勉強になるかもしれ
ません。
プレビューを表示するためにどうすればい
いのか考えあぐねていたら、ここを読んでみて
ピンと来た気がします。毎度長文で申し訳あり
ません。
Print A Text Through A Printer Using PyQt4
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の導入方法について
ちょうどカスタムオブジェクトが描かれているべきところに、
灰のつぶのような小さな点が見えたので、もしやと思い、拡
大ボタンを押して、1500%くらいまで 拡大してみました。
すると、豆粒から見ても豆粒のような、灰カスのような文字が、
大きさはともかくとして、正確に表示されていました。
空白であるにせよ、そこに文字が入り込むだけのスペース
が空いています。その空白の左はじに、灰粕のように、黒い粉
がついています。painterのフォントサイズだけ1以下にされて
しまったような外観です。
つまり、QTextEdit中には通常の表示がなされているはずのカス
タム オブジェクトが、プレビュー画面で表示したときは、どん
なにFontをいじっても、蟻よりも小さくなっています。
もちろん、そのままプリントしても、その通りの文字でした。
さすがプレビューとは言えない状況でした。
私のエディタは、Wordソフトのように、ページネーションが行わ
れているので、QTextDocument or QTextEdit.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以外に追加しても
怒られませんよね?