2016/10/13(木) [n年前の日記]
#1 [ruby] Windows10 + Ruby/Tk でエクスプローラからファイルをD&Dしてファイルパスを取得
Windows10 x64 + Ruby 2.2.5 p319 + Ruby/Tk + TkDND 2.8 で、エクスプローラからファイルをD&D(ドラッグアンドドロップ)して、ファイルパスを取得できるか実験。
参考ページは以下。
_[ruby-list:49771] TkDND での日本語名の扱い
_DebianでRubyからTcl/TkのTkDNDを利用してドラッグアンドドロップを実装する -- ぺけみさお
_tkdnd_test.rb
スクリプトを実行して表示されたウインドウに、エクスプローラからファイルをD&Dしてみた。
できたっぽい。
が、日本語ファイル名は、たしかに化けてるな…。
_[ruby-list:49771] TkDND での日本語名の扱い で紹介されてる変換処理を入れてみた。ついでに、複数ファイルを渡した時に全部処理するようにしてみた。
_tkdnd_test2.rb
文字化けしてないように見える。
が。 _[ruby-list:50353] [再]Re: TkDND での日本語名の扱い によると、空白が入ったファイル名を渡したり、\が入ったファイル名を渡すとおかしくなるそうで。試してみたところ、たしかにエラーが表示された。このあたり、なかなか厳しいものがあるようで。
参考ページは以下。
_[ruby-list:49771] TkDND での日本語名の扱い
_DebianでRubyからTcl/TkのTkDNDを利用してドラッグアンドドロップを実装する -- ぺけみさお
_tkdnd_test.rb
# Ruby/Tk + tkDND でファイルのドロップを受け付けるかテスト # Tk拡張を導入していないと動作しない。 # # [ruby-list:49771] TkDND での日本語名の扱い # http://ruby-list.ruby-lang.narkive.com/lx7VFWDo/ruby-list-49771-tkdnd # # DebianでRubyからTcl/TkのTkDNDを利用してドラッグアンドドロップを実装する -- ぺけみさお # https://www.xmisao.com/2013/07/25/ruby-tkdnd-linux.html require 'tk' require "tkextlib/tkDND" Tk::TkDND::DND label = TkLabel.new { text "Please File Drop" pack } txt = TkText.new(nil){ dnd_bindtarget('text/uri-list','<Drop>', "%D") { |d| p d insert('end',d[0]) insert('end',"\n") } pack } TkButton.new { text "Exit" command "exit" pack } Tk.mainloop
スクリプトを実行して表示されたウインドウに、エクスプローラからファイルをD&Dしてみた。
できたっぽい。
が、日本語ファイル名は、たしかに化けてるな…。
_[ruby-list:49771] TkDND での日本語名の扱い で紹介されてる変換処理を入れてみた。ついでに、複数ファイルを渡した時に全部処理するようにしてみた。
_tkdnd_test2.rb
require 'tk' require "tkextlib/tkDND" require 'nkf' Tk::TkDND::DND label = TkLabel.new { text "Please File Drop" pack } txt = TkText.new(nil) { dnd_bindtarget('text/uri-list','<Drop>', "%D") { |d| d.each { |s| # 日本語ファイル名を渡した時におかしくなるので変換処理をする u8str = s.encode("iso-8859-1","utf-8").encode("iso-8859-1","utf-8") u8str.encode!('cp932', 'utf-8') puts u8str insert('end',u8str) insert('end',"\n") } } pack } TkButton.new { text "Exit" command "exit" pack } Tk.mainloop
文字化けしてないように見える。
が。 _[ruby-list:50353] [再]Re: TkDND での日本語名の扱い によると、空白が入ったファイル名を渡したり、\が入ったファイル名を渡すとおかしくなるそうで。試してみたところ、たしかにエラーが表示された。このあたり、なかなか厳しいものがあるようで。
◎ TkDNDの導入方法。 :
Windows10 x64 + Ruby 2.2.5 p319 + Ruby/Tk の環境で、TkDND も含めたTk拡張(?)を使うには…。
とりあえず、ActiveTcl が必要。 _Download Tcl | ActiveState から入手してインストールする。たしか、自分の環境では、Windows x86(32bit版)、8.6.4.1 をインストールしたような。 セットアップファイルは、ActiveTcl8.6.4.1.299124-win32-ix86-threaded.exe、だった気がする。
次に、ActiveTcl に、TkDND をインストールする。tclsh と打つとプロンプトが「%」になるので、ActiveTcl についてきた teacup なるパッケージマネージャを使ってネット経由でインストール。
最後に、Ruby/Tk からTk拡張を使えるようにする。
このあたりは色々やり方があるらしいけど、自分の環境ではこの方法でやってたり。昔試した時は、この方法なら ocra を使ってRubyスクリプトをexe化する時も問題が出なかったはず。
_2016/10/03の日記 や、 _2015/12/10の日記 にもそのへんメモしてあった、とメモ。
とりあえず、ActiveTcl が必要。 _Download Tcl | ActiveState から入手してインストールする。たしか、自分の環境では、Windows x86(32bit版)、8.6.4.1 をインストールしたような。 セットアップファイルは、ActiveTcl8.6.4.1.299124-win32-ix86-threaded.exe、だった気がする。
次に、ActiveTcl に、TkDND をインストールする。tclsh と打つとプロンプトが「%」になるので、ActiveTcl についてきた teacup なるパッケージマネージャを使ってネット経由でインストール。
% teacup install tkdndインストールできたら、exit と打って抜ける。
最後に、Ruby/Tk からTk拡張を使えるようにする。
ActiveTclインストールフォルダ\lib\teapot\package\win32-ix86\lib\の中に入ってるファイルやフォルダを、
Ruby2.2インストールフォルダ\lib\tcltk\の中にごっそりコピー。
このあたりは色々やり方があるらしいけど、自分の環境ではこの方法でやってたり。昔試した時は、この方法なら ocra を使ってRubyスクリプトをexe化する時も問題が出なかったはず。
_2016/10/03の日記 や、 _2015/12/10の日記 にもそのへんメモしてあった、とメモ。
[ ツッコむ ]
#2 [python] PySideでマウスを動かしてお絵かき
Windows10 x64 + Python 2.7.11 + PySide 1.2.4 で、ウインドウ上でマウスを動かすと何かを描ける、てな処理を QGraphics* を使って試してみたり。
_drawing_pyside_4.py
_ball.png
これで一応できた、のかな。
Qtには、ビットマップデータ相当として使える QPixmap てのがあるわけだけど。その QPixmap に対しては、QPainter を使って何か描き込むことができるわけで。
しかし、その QPixmap を渡して生成した QGraphicsPixmapItem の見た目を更新する方法がどうにも分からず。
結局、生成時に作った QPixmap を更新するたびに、QGraphicsPixmapItem の setPixmap() で設定し直してみたら、見た目も更新されるようになったけど…。果たしてコレでいいのだろうか…?
もしかして、QGraphicsPixmapItem が持ってる QPixmap は、QGraphicsPixmapItem の生成時、あるいは setPixmap() を呼んだ時に渡された QPixmap の内容を丸々コピーして持ってたりするのだろうかと。仮にそうであれば、生成時に渡した QPixmap を後から更新したところで、見た目も即座に更新されるわけでは無い、てのも分かる気もする。が、実際はどういう仕組みになっているのやら。
それと、どうせ QGraphicsPixmapItem が QPixmap を持っているなら、その QPixmap に直接描き込んでしまえばいいのではないか、とも思ったのだけど。試してみたところ、Pythonスクリプトが強制終了してしまって。となると…。
よく分からないと言えば…。QGraphicsView を使うとスクロールバーがなんだか中途半端な長さで出てくるのだけど、コレって何をどうやって設定したり使用したりするのだろう…。今後の課題。
_drawing_pyside_4.py
_ball.png
""" PySideでウインドウに描画。 マウスを動かしてお絵かきできる。 QGraphics* を使う。 ヲドリテヒヅル PyQtでイメージビューワ http://melpystudio.blog82.fc2.com/blog-entry-138.html """ import sys from PySide.QtCore import * from PySide.QtGui import * width = 640 height = 480 brushPath = 'ball.png' class ImageViewScene(QGraphicsScene): """ メインビューと関連付けられる Scene """ def __init__(self, *argv, **keywords): super(ImageViewScene, self).__init__(*argv, **keywords) self.buttonFlag = False self.pixmap = QPixmap(width, height) self.pixmap.fill() self.brushImage = QPixmap(brushPath) # Scene に Item を追加 self.imgItem = QGraphicsPixmapItem(self.pixmap) self.addItem(self.imgItem) def mouseDoubleClickEvent(self, event): pass def mousePressEvent(self, event): """ マウスボタンが押された際の処理 """ if event.button() == Qt.LeftButton: self.buttonFlag = True self.drawing(event) elif event.button() == Qt.RightButton: self.pixmap.fill() self.imgItem.setPixmap(self.pixmap) def mouseMoveEvent(self, event): """ マウスカーソル移動中の処理 """ if self.buttonFlag: self.drawing(event) def mouseReleaseEvent(self, event): """ マウスボタンが離されたときの処理 """ if event.button() == Qt.LeftButton: self.buttonFlag = False def drawing(self, event): """ ブラシで描画 """ x = event.scenePos().x() y = event.scenePos().y() x -= self.brushImage.width() / 2 y -= self.brushImage.height() / 2 qp = QPainter() qp.begin(self.pixmap) qp.drawPixmap(x, y, self.brushImage) qp.end() del qp # 描画更新する方法が分からない… # 仕方なく、pixmap を再設定してるけど…これでいいの? self.imgItem.setPixmap(self.pixmap) # self.imgItem.update() # self.update() class ImageViewer(QGraphicsView): """ メインとなるビュー """ def __init__(self): super(ImageViewer, self).__init__() self.setCacheMode(QGraphicsView.CacheBackground) self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing ) scene = ImageViewScene(self) self.setScene(scene) scene.setSceneRect(QRectF(self.rect())) def resizeEvent(self, event): """ ビューをリサイズ時にシーンの矩形を更新 """ super(ImageViewer, self).resizeEvent(event) self.scene().setSceneRect(QRectF(self.rect())) if __name__ == '__main__': app = QApplication(sys.argv) viewer = ImageViewer() viewer.show() sys.exit(app.exec_())
これで一応できた、のかな。
Qtには、ビットマップデータ相当として使える QPixmap てのがあるわけだけど。その QPixmap に対しては、QPainter を使って何か描き込むことができるわけで。
しかし、その QPixmap を渡して生成した QGraphicsPixmapItem の見た目を更新する方法がどうにも分からず。
結局、生成時に作った QPixmap を更新するたびに、QGraphicsPixmapItem の setPixmap() で設定し直してみたら、見た目も更新されるようになったけど…。果たしてコレでいいのだろうか…?
もしかして、QGraphicsPixmapItem が持ってる QPixmap は、QGraphicsPixmapItem の生成時、あるいは setPixmap() を呼んだ時に渡された QPixmap の内容を丸々コピーして持ってたりするのだろうかと。仮にそうであれば、生成時に渡した QPixmap を後から更新したところで、見た目も即座に更新されるわけでは無い、てのも分かる気もする。が、実際はどういう仕組みになっているのやら。
それと、どうせ QGraphicsPixmapItem が QPixmap を持っているなら、その QPixmap に直接描き込んでしまえばいいのではないか、とも思ったのだけど。試してみたところ、Pythonスクリプトが強制終了してしまって。となると…。
- QGraphicsPixmapItem が持ってる QPixmap は、デスクトップ上の描画にせっせと使ったりしてる関係で、中身を変更しちゃダメだよ、読み出しはともかく書き込みはNGだよ、ということになっている、とか?
- あるいは、中身を変更したいならしかるべき手順を踏んでから更新しないとダメだよ、ということになっている、とか?
よく分からないと言えば…。QGraphicsView を使うとスクロールバーがなんだか中途半端な長さで出てくるのだけど、コレって何をどうやって設定したり使用したりするのだろう…。今後の課題。
[ ツッコむ ]
#3 [neta][anime] BS朝日とBSフジはいっそアニメを放送しないでくれないものか
BS朝日とBSフジは、どうしてアニメ番組の放送時間がガンガンずれるのか…。何かの嫌がらせですか。HDDレコーダの予約録画がグチャグチャだよ…。
多少ずれても問題を起こさない時間帯や曜日が他にあるのに、どうしてわざわざ、あの曜日・時間帯に…。都市圏の地上波放送と照らし合わせるとあそこの曜日・時間帯になっちゃう、みたいなことなんだろうか。
多少ずれても問題を起こさない時間帯や曜日が他にあるのに、どうしてわざわざ、あの曜日・時間帯に…。都市圏の地上波放送と照らし合わせるとあそこの曜日・時間帯になっちゃう、みたいなことなんだろうか。
[ ツッコむ ]
以上、1 日分です。