Hello World / plɹoM ollǝH

Programmers Live in Vain

QScrollAreaの罠にハマる

いつものようにLayoutにButtonを追加するが

一定サイズ以下に縮まないしスクロールバーも出ない

f:id:dungeonneko:20160209014920g:plain

# conding: utf-8
import sys
from PySide.QtCore import *
from PySide.QtGui import *

# entry point
if __name__ == '__main__':
    myapp = QApplication(sys.argv)
    widget = QScrollArea()
    widget.setWidgetResizable(True)

    # いつもの
    layout = QVBoxLayout(widget)
    widget.setLayout(layout)

    layout.addWidget(QPushButton('OK!'))
    layout.addWidget(QPushButton('OK!'))
    layout.addWidget(QPushButton('OK!'))
    layout.addWidget(QPushButton('OK!'))
    layout.addWidget(QPushButton('OK!'))
    layout.addWidget(QPushButton('OK!'))
    layout.addWidget(QPushButton('OK!'))
    layout.addWidget(QPushButton('OK!'))

    widget.show()
    sys.exit(myapp.exec_())

Widgetを一つはさむと何故か想定どおりに動く

f:id:dungeonneko:20160209014222g:plain

    # 内側にWidgetを1つ作ってあげる
    inner = QWidget()
    layout = QVBoxLayout(inner)
    inner.setLayout(layout)
    widget.setWidget(inner)

QListWidget 文字列フィルタリングしてみる

文字列でフィルタリングできるリストビューがあれば

人生の複雑な状況も整理できるかもしれない

f:id:dungeonneko:20160206230506g:plain

# conding: utf-8
import sys
from PySide.QtCore import *
from PySide.QtGui import *

class MyListWidget(QWidget):
    def __init__(self, data, parent=None):
        super().__init__(parent)
        layout = QVBoxLayout()
        self.__filter = QLineEdit()
        self.__lsview = QListWidget()

        self.setLayout(layout)
        layout.addWidget(self.__filter)
        layout.addWidget(self.__lsview)

        self.__filter.textChanged.connect(self.__refresh)
        self.__data = data
        self.__refresh()

    def __refresh(self):
        self.__lsview.clear()

        # 文字列でフィルタリング
        s = self.__filter.text()
        for d in self.__data:
            if len(s) > 0 and s not in d:
                continue
            self.__lsview.addItem(QListWidgetItem(d))

# entry point
if __name__ == '__main__':
    myapp = QApplication(sys.argv)
    widget = QWidget()
    layout = QHBoxLayout(widget)

    # ややこしいデータを挿入する
    mylist = MyListWidget((
        '俺がお前でお前が俺で嫁は関係ない',
        '俺は俺でお前はお前で嫁は嫁だからあんまり関係ない',
        'お前のものは俺のもので俺のものは嫁のもの',
        '俺もお前でお前も俺で嫁は関係ない',
        '俺もお前もあいつもこいつも嫁も関係ない',
        '俺とお前が嫁で嫁は実は婿だった訳だ',
        'お前の嫁が俺の嫁なわけがない',
        'えっ?俺がお前の嫁なの?'))

    widget.setLayout(layout)
    layout.addWidget(mylist)
    widget.show()
    sys.exit(myapp.exec_())

駄目でした

QComboboxにはOrderedDictが良さげ

Comboboxのインデックスと処理が1:1だと便利

dictは追加した要素を不定の順序でイテレートするので

挿入順を保存したい場合は OrderedDict を使う

f:id:dungeonneko:20160206021014g:plain

# conding: utf-8
import sys
from PySide.QtCore import *
from PySide.QtGui import *
import collections

# entry point
if __name__ == '__main__':
    myapp = QApplication(sys.argv)
    widget = QWidget()
    layout = QHBoxLayout(widget)
    lhs = QSpinBox()
    ope = QComboBox()
    rhs = QSpinBox()
    btn = QPushButton('Calc')
    ans = QLabel('???')

    widget.setLayout(layout)
    layout.addWidget(lhs)
    layout.addWidget(ope)
    layout.addWidget(rhs)
    layout.addWidget(btn)
    layout.addWidget(ans)

    # 辞書に追加した順序が保持される
    operators = collections.OrderedDict((
        ('Add', lambda x, y : x + y),
        ('Sub', lambda x, y : x - y),
        ('Mul', lambda x, y : x * y),
        ('Div', lambda x, y : x / y),
    ))

    # コンボボックスに追加
    ope.addItems(list(operators.keys()))

    # 計算ボタンがおされたときの処理
    def calc():
        x = operators[ ope.currentText() ](lhs.value(), rhs.value())
        ans.setText(str(x))

    # ボタン押下イベントに接続
    btn.clicked.connect(calc)

    widget.show()
    sys.exit(myapp.exec_())

Signalの使いかたをよく忘れるのでメモ

これでGUIピタゴラ装置作ったら仕事してる振りできる

f:id:dungeonneko:20160204225915g:plain

# conding: utf-8
import sys
from PySide.QtCore import *
from PySide.QtGui import *

# ほげ~
class Hoge(QLabel):
    # 文字列を引数に渡すシグナルを定義
    textChanged = Signal(str)

    # 初期化
    def __init__(self, parent=None):
        super().__init__(parent)

    # setTextが呼ばれたらラベルを書き換えて一秒後にシグナルを発信
    def setText(self, text):
        super().setText(text)
        QTimer.singleShot(1000, lambda : self.textChanged.emit(text))

# entry point
if __name__ == '__main__':
    myapp = QApplication(sys.argv)

    widget = QWidget()
    layout = QVBoxLayout(widget)
    lineed = QLineEdit()
    label0 = Hoge()
    label1 = Hoge()
    label2 = Hoge()
    label3 = Hoge()
    label4 = Hoge()

    widget.setLayout(layout)
    layout.addWidget(lineed)
    layout.addWidget(label0)
    layout.addWidget(label1)
    layout.addWidget(label2)
    layout.addWidget(label3)
    layout.addWidget(label4)

    lineed.textChanged.connect(lambda s : label0.setText(s))
    label0.textChanged.connect(lambda s : label1.setText(s))
    label1.textChanged.connect(lambda s : label2.setText(s))
    label2.textChanged.connect(lambda s : label3.setText(s))
    label3.textChanged.connect(lambda s : label4.setText(s))

    widget.show()
    sys.exit(myapp.exec_())

C++構造体のXmlシリアライザを自動生成したい

C#だったら属性を書くだけで済むけれど、C++はそういうわけにはいかないのでXMLで定義したフォーマットからコードを生成するスクリプトを書いた。

まずはデータフォーマットをXmlで表記する。

<?xml version='1.0' encoding='UTF-8'?>
<Root>
    <Type name="Scene">
        <Type name="Material">
            <Type name="Property">
                <value name="Name" type="String"/>
                <value name="Value" type="Float[]"/>
            </Type>
            <value name="Name" type="String"/>
            <value name="Properties" type="Property{}"/>
        </Type>
        <Type name="Mesh">
            <Type name="Vertex">
                <value name="Position" type="Float[]"/>
            </Type>
            <value name="Name" type="String"/>
            <value name="Vertices" type="Vertex[]"/>
            <value name="Indices" type="Integer[]"/>
        </Type>
        <Type name="Model">
            <value name="Name" type="String"/>
            <value name="Material" type="String"/>
            <value name="Mesh" type="String"/>
        </Type>
        <value name="Name" type="String"/>
        <value name="Materials" type="Material{}"/>
        <value name="Meshes" type="Mesh{}"/>
        <value name="Models" type="Model{}"/>
    </Type>
</Root>

このXMLからは次のようなC++コードが生成される

struct Scene {
    struct Material {
        struct Property {
            std::string name;
            std::vector< float > value;
        };

        std::string name;
        std::map< std::string, Property > properties;
    };

    struct Mesh {
        struct Vertex {
            std::vector< float > position;
        };

        std::string name;
        std::vector< Vertex > vertices;
        std::vector< int > indices;
    };

    struct Model {
        std::string name;
        std::string material;
        std::string mesh;
    };

    std::string name;
    std::map< std::string, Material > materials;
    std::map< std::string, Mesh > meshes;
    std::map< std::string, Model > models;
};

void serialize(tinyxml2::XMLElement* out_xml, const Scene::Material::Property& in_value);
void deserialize(Scene::Material::Property& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene::Material& in_value);
void deserialize(Scene::Material& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene::Mesh::Vertex& in_value);
void deserialize(Scene::Mesh::Vertex& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene::Mesh& in_value);
void deserialize(Scene::Mesh& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene::Model& in_value);
void deserialize(Scene::Model& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene& in_value);
void deserialize(Scene& out_value, const tinyxml2::XMLElement* in_xml);

で、次のようなデータを読み込むことが可能になり

<?xml version='1.0' encoding='UTF-8'?>
<Scene>
  <Name>PRIMITIVES</Name>
    <Materials>
        <Material>
            <Name>RED</Name>
            <Properties>
                <Property>
                    <Name>Diffuse</Name>
                    <value>
                        <Float>1.0</Float>
                        <Float>0.0</Float>
                        <Float>0.0</Float>
                        <Float>1.0</Float>
                    </value>
                </Property>
            </Properties>
        </Material>
    </Materials>
    <Meshes>
        <Mesh>
            <Name>TRIANGLE</Name>
            <Vertices>
                <Vertex>
                    <Position>
                        <Float>0.0</Float>
                        <Float>1.0</Float>
                        <Float>0.0</Float>
                    </Position>
                    <Position>
                        <Float>-0.866</Float>
                        <Float>-0.5</Float>
                        <Float>0.0</Float>
                    </Position>
                    <Position>
                        <Float>0.866</Float>
                        <Float>-0.5</Float>
                        <Float>0.0</Float>
                    </Position>
                </Vertex>
            </Vertices>
            <Indices>
                <Uint>0</Uint>
                <Uint>1</Uint>
                <Uint>2</Uint>
            </Indices>
        </Mesh>
    </Meshes>
    <Models>
        <Model>
            <Name>TRIANGLE_RED</Name>
            <Material>RED</Material>
            <Mesh>TRIANGLE</Mesh>
        </Model>
    </Models>
</Scene>

次のように使う。

int main()
{
    Scene scene;

    // 読み込み
    tinyxml2::XMLDocument doc;
    doc.LoadFile("deserialize_test.xml");
    deserialize(scene, doc.FirstChildElement("Scene"));

    // 書き込み
    tinyxml2::XMLDocument doc2;
    auto* elem = doc2.NewElement("Scene");
    doc2.InsertFirstChild(elem);
    serialize(elem, scene);
    doc2.SaveFile("serialize_test.xml");

    return 0;
}

おとなしくflatbuffersを使ってね

TransBook T90Chi T90CHI-32G を買ったあとやった事

コード書き専用マシンとして ¥30,000 で購入

不要なソフトウェアを削除
Windows10 にアップグレード
Visual Studio Community 2015 をインストー
  • Custom → C++ のみ選択

容量が32GBなので死にそう。SDカード買って仮想HD化する予定

ffmpeg flv to mp4

ffmpegを使ってflvをコンバートしたら動画がカクカクになってしまったのでメモ

環境

Windows 8.1 + ffmpeg static build

現象
  • WMPではカクカクする
  • GOM Playerで見ると普通の動画に見える
  • Chromeではスローモーション再生
  • 詳細情報を見るとフレームレートが1000になっている
  • FLVのフレームレートは30とか普通の数字
テスト
ffmpeg -i test.flv test_raw.mp4
ffmpeg -i test.flv -vcodec mpeg4 test_codec.mp4
ffmpeg -i test.flv -r 60 -vcodec h264 test_60fps.mp4
ffmpeg -i test.flv -vsync passthrough test_vsync.mp4
結果
  1. 引数なしはカクカクな動画ができる (コーデックはh264)
  2. ビデオコーデックをmpeg4にするとカクカクしないけど汚い
  3. 明示的にビデオコーデックとフレームレートを指定すると解決した
  4. -vsync passthroughオプションでfpsがいい感じに設定されるっぽい