スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Qtウィジエットの背景色の変更とレイアウトへの動的追加

いやはや、シロウトはこんな簡単なところでもはまれる。ハズいが忘れるといやなのでやっぱり書いておく。このサンプルは以下の二つの点を実現するものである。

1. QWidgetの背景色を変更する。
2. 順次QWidgetを生成しながら、レイアウトに追加して表示を更新していく。


#include "widgettest.h"
#include "ui_widgettest.h"
#include

WidgetTest::WidgetTest(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::WidgetTest)
{
ui->setupUi(this);
QLayout *layout = new QHBoxLayout;
ui->panelBase->setLayout(layout);

QWidget *panels[6];
QColor colors[6] = {Qt::red, Qt::blue, Qt::green, Qt::yellow, Qt::magenta, Qt::cyan};

for(int i = 0; i < 6; i++){
panels[i] = new QWidget(ui->panelBase);
QPalette palette = panels[i]->palette();
palette.setColor(QPalette::Window, colors[i]);
panels[i]->setPalette(palette);
panels[i]->setAutoFillBackground(true);
panels[i]->setMinimumSize(100, 100);
layout->addWidget(panels[i]);
panels[i]->show();
repaint();
sleep(1);
}
}


QtCreatorで作成したフォームはQtCreatorで作成したフォーム

のように極めて適当なもの。QMainWindowの上に、動的に生成して配置するウィジェットの親になるQWidget(panelBase)を一つ置いただけである。panelBaseには子ウィジェットが最初は何もないので、Designer画面ではpanelBase上にレイアウトを指定することができない。

そこで、ソース中では水平ボックスレイアウトを新規に作成して、これをpanelBaseに設定している。もしあらかじめDesigner画面の方で仮に子ウィジェットを一つ以上配置して、レイアウトを指定済みだと、後からレイアウトを追加することはできない。

各ウィジェットはデフォルトで親から引き継いだカラーパレット(QPalette)を持っており、パレット内では抽象的な役割(ColorRole)と、その役割に対する実際の色(QColor)のペアがいくつか登録されていて、実際に使用する場合は役割の方を指定して使うことになる。

ColorRoleの各enumの意味
ColorRoleのenum値説明
QPalette::Window一般的な背景色
QPalette::BackgroundObsolete。代わりにWindowを使用すべき。
QPalette::WindowText一般的なフォアグラウンドカラー
QPalette::ForegroundObsolete。代わりWindowTextを使うべき。
QPalette::Base主にテキスト入力ウィジェットの背景色として使われるが、コンボボックスの背景やツールバーハンドルの背景色としても使われる。通常は白か他の明るい色が使われる。
QPalette::AlternateBase表計算などで見られる、一行おきに背景色を変える場合に使われる第2の背景色。
QPalette::ToolTipBaseツールチップや、"What is this?"の表示の背景色に使われる。ツールチップの場合は、パレット自体が、inactive用のものが用いられる。
QPalette::ToolTipTextツールチップや、"What is this?"の表示の文字色に使われる。
以下は、GUIに3D効果を加えるため等に用いられる色。
QPalette::Buttonボタン用の背景色。スタイルによってはWindowとは異なる。
QPalette::ButtonTextボタン用の描画色。
QPalette::BrightTextボタンを押している間などに用いられる、WindowTextとははっきりと違い、かつDark等とははっきりコントラストの差がつく色。
QPalette::LightButtonよりは明るい色。
QPalette::MidlightButtonとLightの中間の明るさ。
QPalette::DarkButtonよりは暗い色。
QPalette::MidButtonとDarkの中間。
QPalette::Shadow非常に暗い色。デフォルトでは黒。
以下はテキスト表示に使用される色。
QPalette::Highlight現在選択されている項目を表す色。デフォルトではダークブルー。
QPalette::HighlightedTextハイライト表示されているテキストの色。HighLightとはっきりコントラストのある色。デフォルトでは白。
QPalette::Linkまだたどっていないハイパーリンク。デフォルトでは青。
QPalette::LinkVisitedすでにたどったハイパーリンク。デフォルトではマゼンタ。

 
 ということで、QWidgetの場合は、背景色を変えるということは、パレット中のWindowロールの色を変更すればよいことになる。このサンプルでは、まず各ウィジェットから現在のパレットを取得し、そのWindowロールの色だけをcolors[i]に変更して、そのパレットをウィジェットに設定し直している。

あとは、実は動的にウィジェットをレイアウトに追加といっても、最初にまとめて生成するのとほとんど違いはない。単に、一個ウィジェットを新しく追加するたびに、repaint()で表示を更新している。update()だと、描画リクエストが次回のイベント処理までバッファされてしまうので数個分まとめて表示されることになる。

表示されるウィンドウ
スポンサーサイト

dnsmasqによるLAN内DNSとDHCPの運用

玄箱ProにDebian Squeezeをインストールしてから、自宅LAN内のDNS(マシン名からローカルIPアドレスの検索)と、DHCPサーバをこれにやらせることにした。やはり自宅内LAN専用のDNSがあるとどのマシンにアクセスするのも名前でできるので便利である。一台のマシンだけなら/etc/hostsに全部書いてもよいが、数台あるともう統一するのが面倒になってくる。さらに仮想マシンを立てたりすることを考えるとなおさらである。また、できれば、IPアドレスからの逆引きにも対応できることが望ましい。

最初は、定番ということでBINDとISC DHCPの組み合わせで、ごちゃごちゃと調べて一応動的IPアドレス割り当てのマシンもLAN内DNSに動的に登録されるようにできたのだが、どうも丸一日程度動かしていると、カーネルのいわゆるOOM-killerに引っかかってnamedのプロセスがkillされてしまうという現象が発生した。ほんの数台しかないマシンを管理するのにBINDを持ち出すのも大げさな気もしてきたので、Debianではよく使われているらしい、より軽量で小規模ネットワークに向いたdnsmasqというパッケージを使ってみることにした。dnsmasqは、正確にはDNSサーバではなくてDNSキャッシュサーバということらしい。一次的な情報は、LAN内部に関しては/etc/hostsから参照し、自分で解決できない外部の名前については外部DNSに問い合わせる。さらにDHCPサーバ機能もあわせ持っている上、DHCPでアドレスを割り当てたマシンを自動的にDNSに登録することもできる。私の目的には十分すぎる機能を持っている。

ということで、LAN内のマシンについては玄箱Proの/etc/hostsには

127.0.0.1 localhost.localdomain localhost
192.168.1.1 gateway.mydomain.com gateway router
192.168.1.2 kurobako.mydomain.com kurobako mail mx www
192.168.1.3 host1.mydomain.com host1
192.168.1.4 host2.mydomain.com host2
192.168.1.5 host3.mydomain.com host3

のように(ドメイン名とホスト名は例。ドメイン名は、何も取得していなければ、"mydomain.com"のかわりにlocaldomainでいいだろう)記述しておき、/etc/dnsmasq.confの方は、コメントを除くと

domain-needed
bogus-priv
local=/mydomain.com/
interface=eth0
expand-hosts
domain=mydomain.com
dhcp-range=192.168.1.10,192.168.1.100,12h
dhcp-host=host1,11:22:33:44:55:66,192.168.1.3
dhcp-host=host2,11:22:33:44:55:67,192.168.1.4
dhcp-host=host3,11:22:33:44:55:68,192.168.1.5
dhcp-option=option:router,192.168.1.1
mx-host=mydomain.com,kurobako.mydomain.com,10
log-queries
log-dhcp

のようにしておく(MACアドレスも例、自分のハードウェアに合わせる)。この設定ファイルでDNSもDHCPも両方設定できるので簡単なものである。上の例では、host1、host2、host3にはそれぞれ固定のIPアドレスが振られ、それ以外のマシンには192.168.1.10から192.168.1.100までの動的なIPアドレスが振られる。動的にIPアドレスが振られたマシンも、自動的にDNSのデータベースに登録されて、LAN内では名前で通信できるようになる上に、IPアドレスからの逆引きもできることが確認できた。

しばらく動かしても問題もないようなので、当面これで運用することにする。



玄箱Pro Debian Squeeze化の手順

基本的に前項で紹介した出典の丸写しなのであるが、これらのページが消滅したら自力では思い出せそうにないのでここに手順をメモっておく。

クロスコンパイル用ツールチェインの用意
mkdir -p ~/kuro
cd ~/kuro
wget 'http://buffalo.nas-central.org/download/LSPro_ARM9/DevelopmentTools/CrossToolchains/CodeSourcery/arm-2007q3-53-arm-none-eabi-i686-pc-linux-gnu.tar.bz2'
tar xjvf arm-2007q3-53-arm-none-eabi-i686-pc-linux-gnu.tar.bz2
cd arm-2007q3/bin/
wget 'http://downloads.nas-central.org/LSPro_ARM9/DevelopmentTools/CrossToolchains/mkimage'
chmod +x mkimage

環境変数の設定
export ARCH=arm
export CROSS_COMPILE=arm-none-eabi-
export PATH=~/kuro/arm-2007q3/bin/:${PATH}

カーネルソースの入手
ここでは、標準カーネルではなくてorionリポジトリの方のをいただいてきた。
cd ~/kuro
git clone git://git.kernel.org/pub/scm/linux/kernel/git/nico/orion.git
cd orion
make mrproper
make orion5x_defconfig

カーネルイメージの作成、玄箱Proへの転送
make menuconfigでは、ARMまわりの設定は既に上のdefconfigで行われているので、NFSやオートマウンタまわりの設定だけ追加した。またdevioがなければインストールしておくこと。scpは玄箱Proに転送さえできればftpであろうがsmbclientであろうがWindowsからであろうが構わない。ここでは玄箱Proのホスト名がkuroと仮定されている。

make menuconfig 
make zImage
devio > foo 'wl 0xe3a01c05,4' 'wl 0xe38110e5,4' # For kuropro/lspro
cat foo arch/arm/boot/zImage > zImage.new
mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e 0x00008000 -n 'linux' -d zImage.new uImage
scp uImage kuro:/tmp/

カーネルモジュールのコンパイルと玄箱Proへの転送
ここでは細かいことは気にせず開発マシンの方でモジュールのインストールを行っている。i686マシンにArmのバイナリモジュールがインストールされるので気持ち悪い人もいるかもしれないが、場所は/lib/modules/カーネルバージョン以下に限定されているので問題になることはあるまい。

make modules
su
make modules_install
cd /
tar czf /tmp/modules.tgz lib/modules/2.6.38-rc6-12018-g7780c80/
scp /tmp/modules.tgz kuro:/tmp/

玄箱Pro側でブートの設定
ssh kuro
cd /
tar xzvf /tmp/modules.tgz
mv /tmp/uImage /boot/uImage-2.6.38-rc6-12018-g7780c80
cd /boot
mv uImage uImage.old
ln -s uImage-2.6.38-rc6-12018-g7780c80 uImage
init 6

あくまでも上記は、すでにユーザランドのバイナリも「玄箱Proの本」などに基づいて、(アーキテクチャ名はarmのままであるにしても)EABI化されている言を前提にしている。一応はカーネルはOABIのバイナリも実行できる設定にはなっているが、基幹ライブラリまでOABIの状態で満足に動作するかどうかはわからない。

次に、ユーザーランドをarmからarmelに移行していく。

armelユーザランドの作成
debootstrap --verbose --arch armel --foreign lenny /armel-chroot http://ftp.de.debian.org/debian
chroot /armel-chroot /debootstrap/debootstrap --second-stage

基本的にはこれで/armel-chroot以下にarmelアーキテクチャのユーザランドファイルシステムツリーが構成される。要はDebianのdebootstrapというツールに全面的にお世話になっている。

バイナリのすげ替え
これはうまくいくことが保証されたプロセスではない。動作中のシステムでいきなりバイナリを入れ替えるので、メモリ上にそのバイナリのイメージが保持されていたり、スワップアウトされていたりすると不整合が起きる可能性が高くなる。そういう事態を避けるために、シングルユーザモードで作業する。しかし私の玄箱Proではランレベル1でもなぜかsambaのプロセスが動いていたりしたので、手動でkillした。
# telinit 1
# ps -ef #ユーザプロセスが動いていないか確認、動いていたらkill
# mount -o bind / /chroot-armel/mnt/
# chroot /chroot-armel/ #前のステップで作成したarmelユーザランドにchrootすることで動作確認
# cd /mnt
# mkdir old
# mv bin sbin lib usr var old # armバイナリをoldディレクトリに移動
# cp -a /bin /sbin /lib /usr /var . # armelバイナリを/以下にコピー(/は今、/mntとして見えている)
# init 6

これで無事再起動に成功したら、あとは /etc/apt/sources.list内のlenny => squeezeと書き換え、

#apt-get update
#apt-get upgrade

を実行しておく。

出典
Armel Debian for the Kurobox Pro - Manual install
Kernel-cross-compile-kurobox-pro
ArmEabiHowto

復活の玄箱Pro

デスクトップのLinuxマシンでsambaのマスターブラウザ等をとりあえずやらせていたのだが、常に立ち上がっているわけではないのでこういった用途には今ひとつぴったりこない。また自宅内LAN用のDNS等、低負荷でかつ常に動いていて欲しいサービスもいくつか他にもあるので、かつて若干使用してその後お蔵入していた玄箱Proを現役復帰させることにした。基本的には玄箱ProにLinux(Debian)をインストールして使う手法は確立されており、書籍や各ブログで扱われており、2年以上前に一応の完結を見ている。ただし、現在の最新版であるDebian 6.0.1(Squeeze)との関連でいうと若干注意すべき点がある。

最大のポイントは、玄箱ProのCPUアーキテクチャであるARMに対して、今まではABI(Application Binary Interface: 機械語ファイルの呼び出しの際のレジスタやメモリの使い方の規約)が2種類あって、システムによってそのどちらかを利用していたのだが、Debian Squeezeでは、EABIと呼ばれる後発のABIのみがサポートされるようになったこと。

今までOABIを利用していた人も、Squeeze以降にアップグレードしたければEABIに統一する必要がある。なお、OABIを使用したシステムはアーキテクチャ名ARM、EABIを利用したシステムはArmelと呼ばれる。

私の玄箱Proは、どういう状況かすっかり忘却の彼方だったが、掘り出して起動してみると、Debianの5.0が正式リリース直前のものがインストールされており、一応起動してログインもできる。どうやらsushi-k氏作成のEBAIユーザーランドがインストールされているらしい。

カーネルはOABIとEABI両方が用意してあるが、システムアーキテクチャ自体はarmとして認識されていた。実はこの状態からapt-getでアップグレードを試みて、ftp元にアーキテクチャarmのアップグレードパッケージがないことから上記のような事情に気がついた次第だ。

そこから若干調べて、システム全体をEABI対応で最新の状態にもっていくことにした。まずはカーネルから、Kernel-cross-compile-kurobox-proに習ってデスクトップマシンでクロスコンパイルする。gitから持ってきたバージョンは、2.6.38-rc6-12018-g7780c80だった。

このカーネルでいったんリブートして、次はユーザーランドの構築に取りかかる。と言っても、armからarmelアーキテクチャへの移行は、今のところ由緒正しい方法というのは存在しないようだ。若干調べた結果、要は動作中のシステムで、(せめてシングルユーザモードで余分なプロセスを動かさず)強引に旧バイナリを削除して新しいユーザランドと入れ替えるという恐ろしげな方法しかないらしい。

ArmEABIHowtoというページを発見し、その"Creating a EABI chroot using debootstrap"の項を参考にarmelのユーザランドを構築する。debootstrapというのはえらい便利なツールである。このようにして作成したユーザランドのうち、直接バイナリが絡むディレクトリであるbin sbin lib usr varあたりを、Migrating arm installation to arm EABI installationの項にしたがってエイヤッと一気に入れ替える。これでうまくいくという保証はまったくない気がするが、運が良ければシステムは騙されて、リブートすればあら不思議自分はarmelシステムだと思い込んでくれる。そうなったらあとは、/etc/apt/sources.listのlennyをsqueezeに書き換えてapt-get updateとupgradeを行えば見事にarmelアーキテクチャのSqueezeシステムのでき上がりとなる。

身の回りの電化製品の消費電力

さて、現在東京在住なので、今回の地震・津波に伴い節電にも協力することにした。効果的に行うために、今一度身の回りにある電化製品の消費電力をチェックしてみる。一般論としては、電気を熱に変えて利用するものが最もW数が大きくなりがちのはずだが。

32型液晶TV 使用時144W 待機時0.1W
石油ファンヒーター 点火時320W 運転時20W
蛍光灯 30W + 38W
電気ポット 1000W
冷蔵庫 70W(モーター) + 120W(電熱装置)
電子レンジ 500W

確かに電気ポットや電子レンジは動作中の消費電力は大きく、実はうちのキッチンでは両者が同時に動作するだけでかなりの確率でブレーカーが落ちる。しかしこれらはいずれも、動作している時間は比較的短い。冷蔵庫にしても実際にコンプレッサーが動作して冷却動作を行っている時間はそんなに長くはない。

そう考えると、実はTVは意外に多くの電力を消費している気がしてきた。私はTVをつけている時間が長いので気にしなければいけないだろう。また、蛍光灯も白熱電球よりは少ないながら、部屋が暗く長時間証明をつけがちなゆえに注意すべきかもしれない。

そしてあとは何といってもPCである。私のPCは2台あって、どちらも特にハイパフォーマンスを狙っているわけでもないので取り立ててパワーを多く消費するわけではないが、それでもおそらくどちらも平常使用時で100Wから200W程度は喰っているのではなかろうか。

以上のことを考慮して、特に計画停電初日は大規模停電を回避するため部屋の明かりもTVも消して、ノートPC一台で情報を収集していた。これから徐々に東京電力の給電能力も回復してくるだろうが、今後も生活を見直して、無駄な電気の使用は個人的に控えたいと思う。それが今回の災害から学べる前向きなことの一つだと思うから。
プロフィール

GM3D

Author:GM3D
FC2ブログへようこそ!

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
FC2カウンター
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QR
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。