Qt: 定番小ワザ集

すぐ忘れる筆者用メモです。
適当に行き会ったものを挙げています。随時追加のつもり。


ラインエディット

テキストを入力

	QString str;

	if ( !str.isEmpty() )
	{
		lineEdit->setText( str );
	}	

テキストを取得

	QString str = lineEdit->text();

パスワード入力モードにする

	lineEdit->setEchoMode( QLineEdit::Password )

プロパティなのでQtDesignerで設定が可能です。

プロパティエディタ


チェックボックス

チェック状態を取得

	if ( checkBox->checkState() == Qt::Checked )
	{
		// チェックされているときの処理
	}
	else
	{
		// チェックされていないときの処理
	}

ファイル選択ダイアログ

	QFileDialog::Options options;
	QString strSelectedFilter;
	QString strFName = QFileDialog::getOpenFileName(
			this, 
			tr( "タイトル文字列" ),
			".",
			tr( "フィルタ文字列" ),
			&strSelectedFilter, options );
			
	if ( !strFName.isEmpty() )
	{
		// ファイルに対する処理
	}

上記のは「ファイルを開く」ダイアログです。「名前をつけて保存」ダイアログの場合はQFileDialog::getSaveFileName()を使います。
フィルタ文字列で複数の拡張子を指定する場合はスペース区切りらしい(“Image(*.tif *.pnt *.jpg)”)。
複数のフィルタを使用する場合は”;;”で区切るらしいです。
つまり、以下のようにするらしいです。

"TIFF image document(*.tif *.tiff);;Portable network graphic(*.png)"

このとき選択されたフィルタは第5引数(上記コードのstrSelectedFilter)に格納されますが、
フィルタ文字列が全て格納されるため(”TIFF image document(*.tif *.tiff)”のようになる)、
ファイル種別ごとに処理を分けたい場合は選択されたファイル名の拡張子を別途調べたほうがよいでしょう。

なお、複数ファイル選択の場合はQFileDialog::getOpenFileNames()関数を使用します。
戻り値はQStringList型です。


フォルダ選択ダイアログ

	QFileDialog::Options options = QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly;

	QString strDir = QFileDialog::getExistingDirectory( 
			this,
			tr("ダイアログタイトル"),
			tr("初期ディレクトリ"), options);

	if ( !strDir.isEmpty() )
	{
		// ファイルに対する処理
	}

ファイルの存在確認

    if ( QFile::exists( "パス名" ) )
    {
        存在する場合の処理
    }

よくあるのが、プログラム内で合成したファイル名のファイルが存在するかどうかを調べるパターンですが、
その場合は以下のようにするといいですかね?
以下の例はTIFファイルに対応するTFWがあるかどうかを調べる例です。

#include <QFileInfo>
    
    QFileInfo info( "TIFFファイル名" );
    QString strDirname = info.absolutePath();
    QString strBasename = info.completeBaseName();
    if ( QFile::exists( strDirname + "/" + strBasename + ".tfw" ) )
    {
        TFWに対する処理
    }

ファイル検索

指定したディレクトリで条件を満たすファイル名のリストを取得するには以下のようにします。

    QDir dir( ディレクトリ名 );
    QStringList strlFilter;
    strlFilter << "*.tif" << "*.jpg";
	QFileInfoList list = dirProj.entryInfoList( strlFilter, QDir::Files );
    for ( int i = 0; i < list.size(); i++ )
    {
        // 各ファイルに対する処理
        // 各ファイル名はlist[i]で取り出す
    }

テーブルウィジェット

構築

QtデザイナでQTableWidgetを配置してtableという名前にしたとします。

    // 不要かも
    table->clear();

    // テーブルサイズを決定
    table->setColumnCount( 3 );
    table->setRowCount( 20 );
	
    // 列のタイトル文字列を一度に指定
    table->setHorizontalHeaderLabels( QStringList() << tr("Title 1") << tr("Title 2" ) << tr("Title 3") );

    // セルを埋める

    table->setItem( 0, 0, new QTableWidgetItem( 何かテキスト );
    table->setItem( 0, 1, new QTableWidgetItem( "" ) ); // 空白の場合
    table->setItem( 0, 2, new QTableWidgetItem( "" ) );
    
    // 行の高さを指定 行ごとに指定する必要がある様子
    table->setRowHeight( 0, 20 );
	
    // 一行選択モードに設定
    table->setSelectionMode( QAbstractItemView::ContiguousSelection );
    table->setSelectionBehavior( QAbstractItemView::SelectRows );

セルの文字列を取り出す

    table->item( ,  )->text()

アイコンをセルに表示

    // セルのアイテムを取得
    QTableWidgetItem *pItem = tableWidget->item( ,  );
    // リソースにアイコンが登録されている場合
    pItem->setIcon( QIcon( ":/icons/icon.png" ) );

指定したアイテムまでスクロール

    // セルのアイテムを取得
    QTableWidgetItem *pItem = tableWidget->item( ,  );
    tableWidget->scrollToItem( pItem );

セルにコントロールを埋め込むには

チェックボックスの場合は簡単で、QTableWidgetItemオブジェクトのsetCheckState()を呼べばいいです。

  QTableWidgetItem *pItemCheck = new QTableWidgetItem();
  pItemCheck->setCheckState( Qt::Checked ); // チェック状態で表示の場合、非チェック状態で表示したい場合はQt::Uncheckedを指定

その他のコントロールの場合の詳細は以下のリンクを参照してください。

参考リンク

スピンボックスなら、
入門
Qt 4 プログラミング

に載っていますし、Qtソースコードのexamples/itemviews/spinboxdelegateに実例があります。

コンボボックスなら、
Combo Boxes in Item Views
がそのものです。

概要は、QStyledItemDelegateクラスの派生クラスを作成して、
3、4つほど仮想関数をオーバーライドしてセルの表示やコントロールとのデータのやり取り方法を規定し、
setItemDelegate()関数でデリゲートを適用します。


プロセス

QProcessクラスを使って管理します。
非同期実行の場合はQProcess::start()、同期実行の場合はQProcess.execute()を呼び出します。

Qtでは非同期実行の場合、標準出力、標準エラー出力を取り出してウィンドウに表示したりすることも簡単にできます。
以下はその例です。

#include <QProcess>

// クラス宣言部

private:
	QProcess m_proc;

private slots:
	// 非同期実行用スロット3点セット
	void proc_finished( int exitCode, QProcess::ExitStatus exitStatus );
	void updateOutput();
	void updateError();

/////////////////////

// 定義部

	// コンストラクタあたりでシグナル−スロット接続
	QObject::connect( &m_proc, SIGNAL(readyReadStandardOutput()), this, SLOT(updateOutput()) );
	QObject::connect( &m_proc, SIGNAL(readyReadStandardError()), this, SLOT(updateError()) );
	QObject::connect( &m_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
		this, SLOT(proc_finished(int, QProcess::ExitStatus)) );

// スロット
void C***::updateOutput()
{
	// 標準出力を取り出して文字列にする
	QByteArray output = m_proc.readAllStandardOutput();
	QString str = QString::fromLocal8Bit( output );
}

void C***::updateError()
{
	// 標準エラー出力を取り出して文字列にする
	QByteArray output = m_proc.readAllStandardError();
	QString str = QString::fromLocal8Bit( output );
}

// プロセス終了時のスロット
void C***::proc_finished( int exitCode, QProcess::ExitStatus exitStatus)
{
	if ( exitStatus == QProcess::CrashExit )
	{
		QMessageBox::warning( this, tr("Error"), tr("Crashed") );
	}
	else if ( exitCode != 0 )
	{
		QMessageBox::warning( this, tr("Error"), tr("Failed") );
	}
	else
	{
		// 正常終了時の処理
	}
}

	// プロセス起動箇所

	QStringList strlArgs;

	strlArgs << 引数1 << 引数2 ・・・
	m_proc.start( "実行するプログラム名", strlArgs );

マウスイベント

QWidgetまたはその派生クラスのウィジェットでマウスイベントが発生したときは、シグナルが発行されるのではなくコールバックが呼び出されます。
それぞれのコールバックは以下のとおりです。

// どれかのボタンが押されたときのコールバック
void MyWidget::mousePressEvent( QMouseEvent *pEvent )
{
	if ( pEvent->button() == Qt::LeftButton )
//	if ( pEvent->buttons() & Qt::LeftButton ) // 複数のボタンが押された場合を想定するならこうする
	{
		// 左ボタンが押されたとき
	}
	else if ( pEvent->button() == Qt::RightButton )
	{
		// 右ボタンが押されたとき
	}
	else if ( pEvent->button() == Qt::MiddleButton )
	{
		// 中ボタンが押されたとき
	}

	// ボタンが押された位置
	QPoint pntLastPos = pEvent->pos();
}

// どれかのボタンが離されたときのコールバック
void MyWidget::mosueReleaseEvent( QMouseEvent *pEvent )
{
}

// マウスが移動したときのコールバック
void MyWidget::mouseMoveEvent( QMouseEvent *pEvent )
{
}
	
// マウスホイールが回されたとき 引数はQWheelEventなので注意!
void MyWidget::wheelEvent( QWheelEvent *pEvent )
{
	// +の値は前方へ、-は後方へ回されたとき
	// delta()の値はまわされた角度の8倍の値らしい
	// 標準的なマウスでは1ステップが15度らしいので、こうするらしい??
	double dSteps = (double)pEvent->delta() / 120.0;
}

デフォルトでは、mouseMoveEvent()関数はいずれかのボタンが押された状態でないと呼び出されないようになっています。
なので、”マウスが押されたフラグ”というのを用意しなくてもいいようになっています。

この動作はmouseTrackingプロパティで制御されており、デフォルトはfalseです。
ボタンが押されていないときでも移動イベントを発生させたいときはsetMouseTracking ( true )を呼び出します。


ハイパーリンクのラベル

まず、ラベルのテキストをHTMLと同じようにハイパーリンクにします。
Qtデザイナを使う場合は以下のようにプロパティを設定します。

これだけでハイパーリンクのラベルができます。


ツリーウィジェット

構築

QtデザイナでtreeWidgetという名前にしたとします。

	// 不要かも??
	treeWidget->clear();

	// ツリーの右側にアイテムの属性を表示するコラムを作成できる。
	// デフォルトは1で、これだと普通のツリー。
	treeWidget->setColumnCount( 1 );

アイテム追加

子アイテムは1つずつ追加することもできるし、まとめて追加することもできます。
まず、トップレベルアイテムから追加します。

	// 追加するアイテムのリスト。
	QList<QTreeWidgetItem *> items;
	
	// アイテムを構築
	// QTreeWidgetItemの第1引数は親アイテム
	// まとめて追加する場合はここはNULL。
	// 第2引数は表示文字列で、QStringList型。
	// リストである理由は、複数のコラムがある場合のため。
	QTreeWidgetItem *item = new QTreeWidgetItem( (QTreeWidget *)NULL, QStringList( str ) );
	items.append( item );

	// 複数のアイテムを詰め込んだ後、ツリーに追加。
	// 第1引数はインデックスで、最初に追加する場合は0。
	treeWidget->insertTopLevelItems( 0, items );

次に、トップレベルのアイテムに子アイテムを追加していきます。
アイテムの構築、アイテムリストの作成までは上記と同じで、アイテムリストの追加だけ異なります。

	// 子アイテムを追加したい親アイテムのポインタ
	QTreeWidgetItem *item = ・・・;

	// 親アイテムに追加
	item->addChildren( items );

ツリーが展開されたタイミングで追加

最初から子アイテムを全て追加するのは効率が悪かろうと思われるので、
ツリーの展開操作が行われたタイミングでそのアイテムの子アイテムを追加するようにすると良かろうと思われます。

展開時に発行されるシグナルはitemExpanded(QTreeWidgetItem *)です。
この引数のQTreeWidgetItemポインタが展開しようととされたアイテムをさしています。
これに対応したスロットを用意して、その中で引数のアイテムに子アイテム追加のコードを記述すると良いでしょう。

表示時点では子アイテムがないので、展開ツマミが表示されません。そこで、強制的に表示させるようにします。
アイテム構築時に以下のようにプロパティを設定します。

	item->setChildIndicatorPolicy( QTreeWidgetItem::ShowIndicator );

末端アイテムに達したときは逆に強制的に展開ツマミを表示しないようにする必要がありますが、
そのときはitem->setChildIndicatorPolicy( QTreeWidgetItem::DontShowIndicator );
を設定します。

子アイテムを削除する

上記のように展開されたタイミングでアイテムを追加する方式の場合は先にすでに追加されている子アイテムを全て削除する必要があります。
一括して削除する場合はQTreeWidgetItem::takeChildren()を呼び出します。

現在の階層を調べる

選択されたアイテムがトップレベルから数えて何階層目かを調べる関数がありそうでありませんでした(探しきれなかっただけかもしれません)。
ここでは、QTreeWidgetItem::parent()が、トップレベルアイテムだとNULLを返すのを利用して以下のようにしてみました。

	QTreeWidgetItem *parent = item;
	int nH = 0;
	while ( parent = parent->parent() )
	{
		nH++;
	}

アイテムにチェックボックス

ツリーのアイテムにチェックボックスを付けるのはpItem->setCheckState( 0, Qt::Checked );とすればいいですが、
問題はチェックのOn/Offをどうやって取得するかでしょう。

チェック状態を取得する場合は、QTreeWidgetが発行するitemChangedシグナルを捕まえます。

例:
	QObject::connect( treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
		this, SLOT(onChecked(QTreeWidgetItem *, int)) );

スロットの引数にチェックのOn/Offがあったアイテムが渡されますが、これだと結局どのアイテムにチェックがあったのかわかりません。
アイテムのテキストで調べるのもいまひとつなので、ここではアイテムに任意のデータを仕込んでおく方法を採用します。
たとえば、アイテムをツリーに追加する前に、pItem->setData( 0, Qt::UserRole, QVariant( 5 ) );
としてアイテムに”5″というデータをセットし、スロット側では
int n = pItem->data( 0, Qt::UserRole ).toInt();のようにしてセットされたデータを取り出します。


リストウィジェット

似たような名前のウィジェットにリストビューというのがあるので気をつけましょう。
リストウィジェットのクラス名はQListWidgetです。

アイテムを追加

    // 不要かも??
    listWidget->clear();
	
    // 文字列を追加する場合
    listWidget->addItem( tr("何か文字列") );

現在のアイテムの文字列を取得

    QListWidgetItem *pItem = listWidget->currentItem();
    QString str = pItem->text();

選択されているアイテムを取得

複数選択が有効になっている場合は現在のアイテムを取得するだけでは足りないので以下のようにします。

    // 選択されているアイテムのリストを取得
    QList<QListWidgetItem *> listItems = listWidget->selectedItems();
    
    // 個別のアイテムに対する処理
    for ( int i = 0; i < listItems.size(); i++ )
    {
        QListWidgetItem *pItem = listItems[i];
    }

選択されているアイテムを削除

Qtヘルプには、アイテムを削除するにはtakeItem()関数を使えとありますが、
この関数は引数に行番号をひとつだけ受け取る形なので、複数選択可の場合、それらをまとめて削除することができません。

複数選択可の場合で複数をまとめて消去する方法は
ここのリンクにあります。

たった一行以下のようにするだけです。

  qDeleteAll( listWidget->selectedItems() );

2次元変換行列

QTransformを利用して変換行列を作成したり、作成した変換行列を図形に適用したりすることができます。

変換行列の作成は以下のようにします。

回転

  QTransform transR;
  transR.rotate( "回転角(度)" );
  transR.rotateRadians( "回転角(ラジアン)")

回転の+方向は反時計回りです。第2引数は回転軸で、省略した場合はZ軸になります。

移動

  QTransform transT;
  transT.translate( "X移動量", "Y移動量" );

拡大・縮小

  QTransform transS;
  transS.scale( "X拡大量", "Y拡大量" );

作成した行列を図形に適用するには以下のようにします。

  // 点に適用
  QPointF pntDst = transR.map( pntSrc );

行列が回転、平行移動、投影変換を表す場合は、mapRect()関数で変換先図形の外接矩形を求めることができます。

  // 変換先図形の外接矩形を求める
  QRectF rcDst = transR.mapRect( rcSrc );

行列要素を直接参照したい場合はm11(), m12()等の関数を利用します。数字が1スタートなので注意!


テキストストリーム小技集

QTextStreamクラスは便利ですが、書式を操作するのは意外に面倒だったりします。

浮動小数

  QFile file( strFName );
  QTextStream strm( &file );
  
  // 浮動小数を"***e+**"の形式に
  strm.setRealNumberNotation( QTextStream::ScientificNotation );
  
  // 浮動小数の桁数を固定
  strm.setRealNumberNotation( QTextStream::FixedNotation );

  // 浮動小数点の桁数を設定
  strm.setRealNumberPrecision( 3 );

列幅を設定

列ごとに列幅を設定する場合は、ひとつ列を出力するたびに設定する必要があります。

  QFile file( strFName );
  QTextStream strm( &file );
  
  // 列を右寄せに設定
  strm.setFieldAlignment( QTextStream::AlignRight );

  // 1列目の文字数を設定  
  strm.setFieldWidth( 20 );
  strm << 1列目の何かテキスト
  
  // 2列目の文字数を設定  
  // 最終列の改行に"endl"を使ってはいけない
  strm.setFieldWidth( 40 );
  strm << 2列目の何かテキスト + "n" << flush;

最終列の改行でendlを使うと、それが1つの列として扱われるので空列が1つ余計に追加される形になり、
余分な空白が末尾に追加されてしまいます。

出力エンコーディングを指定

	// 例:UTF-8にする場合
	strm.setCodec( UTF-8" );

出力エンコードをSJISにした場合、普通にすると「~」が化けると思われます。
この現象についての詳しい説明は以下のリンクにあります。

文字コードについて(シフトJISの問題)

まったくひどい話ですが、これをどうしても直す場合は仕方が無いので以下のようにすると一応治ります
(Winodwsの場合に限ります)。

	strm << str.replace( QChar(0x301C), QChar(0xFF5E) );

リストウィジェット等にファイル名リストを追加するとき

ファイル名に数を含むような場合、例えば”file1,file2,file3,file10,file11,file12″のように
桁数がそろっていないファイルリストをリストウィジェットなどに追加するとき、ウィジェットにソートを任せると
“file1,file10,file11,file12,file2,file3″のように並べられてしまいます。

Windowsならば、StrCmpLogicalW関数がこのような文字列を数字順に上手にソートしてくれます。
そこで、ウィジェットのソートを無効にし、この関数を利用して自前でソートを行ってウィジェットに追加するには以下のようにします。

   1: 
   2: // 自前の比較関数
   3: static bool lessThan( QString &left, QString &right )
   4: {
   5: 	LPCWSTR pszwLeft, pszwRight;
   6: 	pszwLeft = (LPCWSTR)left.unicode();
   7: 	pszwRight = (LPCWSTR)right.unicode();
   8: 	return StrCmpLogicalW( pszwLeft, pszwRight ) < 0;
   9: }
  10: 
  11: // 複数選択したファイルリストをリストウィジェットに追加する関数
  12: void dlgFiles::browseImage()
  13: {
  14: 	QStringList strlFName = QFileDialog::getOpenFileNames( this, "Select files",  "C:", "File(*.*)" );
  15: 	if ( strlFName.size() == 0 )
  16: 		return;
  17: 
  18: 	qSort( strlFName.begin(), strlFName.end(), lessThan );
  19: 
  20: 	for ( int i = 0; i < strlFName.size(); i++ )
  21: 	{
  22: 		listWidget->addItem( strlFName.at( i ) );
  23: 	}
  24: }

QTreeViewQTableViewの場合は、
QSortFilterProxyModelクラスの派生クラスを作成してセットする方法もあるようです。
この方法はまだ使ったことがありません。。以下のGoogle codeのプロジェクトが採用しています。

kamicmd – Modern file manager – Google Project Hosting


日本語を使うには

個別の文字列に適用するにはこちら
アプリケーション全体に適用するにはこちらのリンクが参考になります。

後者の設定をしても英語が使えなくなるということはないはずなので、とりあえず設定しておいて損はなさそうです。

加えて、QTextCodec::setCodecForTr( QTextCodec::codecForLocale() );も同時にやっておきましょう。

Qt5の場合

こちらのリンク
で詳しく説明されています。
今のところはSJISで統一したほうがよさそうです。というわけで、

  QTextCodec::setCodecForLocale( QTextCodec::codecForName("SHIFT-JIS") );

としておきましょう。
また、メッセージボックスやウィンドウタイトルなどで文字列リテラルを扱うような場合は

  QString::fromLocal8Bit("画像ファイルを開けません")

とするととりあえず大丈夫です。

std::stringに変換する場合

上記の問題のためか、日本語を含むQStringからstd::stringに変換する際に
QString::toStdString()関数を使用すると文字化けします。
これはOpenCV等のstd::stringを受け取るライブラリに日本語を含むパスを渡せないということになり、困りものです。
とりあえずの回避策としては、上記のQTextCodec::setCodecForLocale()関数でSJISに設定したとして、

  QString strFName = QFileDialog::getOpenFileName
    ( this, "Select image",  "C:", "Image File(*.*)" );

  std::string str( strFName.toLocal8Bit() );

として、一旦SJIS文字列に変換するという方法があります。


文字列中に2バイト文字が混じっているかどうかをチェックするには

文字列中に日本語が混じっていては困るようなケースは意外と多いかと思います。
ところがこれを確認する方法が意外とありません。
で、下記の方法はちょっと変ですが今のところ問題なくチェックできているようです。

   1: 
   2: 	QTextCodec *pCodec = QTextCodec::codecForName( "ISO 8859-1" );
   3: 	
   4: 	// str が検査対象文字列のQString
   5: 	if ( !pCodec->canEncode( str ) )
   6: 	{
   7: 		// 日本語ありの場合の処理
   8: 	}

プログラムの設定を保存するには

前回プログラムを起動したときに開いたフォルダ名やファイル名を記録しておいて次回また使用したい場合等のように、
何らかのプログラム設定を外部に保存しておきたい場合があります。

このような場合はQSettingクラスを使用します。
典型的な使い方は以下のようなものになるかと思います。

   1: 
   2: // 設定の保存
   3: void MainDialog::closeEvent( QCloseEvent *event )
   4: {
   5: 	QSettings settings( "団体名", "プログラム名" );
   6: 
   7: 	settings.beginGroup( "グループ名" );	
   8: 	settings.setValue( "項目名", "値" );
   9: 	settings.endGroup();
  10: 
  11: 	QWidget::closeEvent( event );
  12: }
  13: 
  14: 
  15: // 設定の読み込み
  16: MainDialog::MainDialog(void)
  17: {
  18: 	setupUi( this );
  19: 
  20: 	QSettings settings( "団体名", "プログラム名" );
  21: 		
  22: 	settings.beginGroup( "グループ名" );	
  23: 	// 文字列の値を取り出す場合
  24: 	QString strSetting = settings.value( "項目名", "値が見つからないときのデフォルト値" ).toString();
  25: 	settings.endGroup();
  26: }
  27: 

QSetting::setValue()関数の第2引数はQVariant型なので、文字列のほかに数値なども保存することができます。

これらの値は、Windowsであればレジストリに保存されます。
そのほかのOSではそれぞれの仕様にあった保存が行われるので、OSの違いを意識する必要は無いようになっています。


スプラッシュウィンドウ

昨今は非常に嫌われるスプラッシュウィンドウですが、どうしても必要な場合もあろうかと思われます。

まずは、スプラッシュウィンドウ用画像を準備します。
透過をサポートしているPNG形式が理想的です。下記のコードは画像の透過をマスクとして非矩形スプラッシュウィンドウを表示します。
以下の例ではリソース:/img/splash.pngに登録したものとします。

   1: 
   2: int main(int argc, char *argv[])
   3: {
   4: 	QApplication app(argc, argv);
   5: 
   6: 	// show splash screen.
   7: 	QPixmap pxmSplash( ":/img/splash.png" );
   8: 	QSplashScreen wndSplash( pxmSplash );
   9: 	wndSplash.setMask( pxmSplash.mask() );
  10: 	wndSplash.show();
  11: 	app.processEvents();
  12: 
  13: 	// 表示中、この間にあれこれ起動処理を記述する
  14: 
  15: 	MainDialog window;
  16: 	window.show();
  17: 	wndSplash.finish( &window );
  18: 
  19:     return app.exec();
  20: }

スプラッシュウィンドウに文字列を表示

そもそもスプラッシュウィンドウが必要な場合のひとつとして、起動に時間がかかるプログラムでユーザが不安にならないようにするためというのが挙げられると思います。
そのような場合、スプラッシュウィンドウが表示されたまま何も進まないと、固まってしまったのではないかとやはり不安にさせてしまいます。
そこで、このような時は何か処理内容をスプラッシュウィンドウに表示したりすると、一応何か進んでいるなと思わせることができます。

スプラッシュウィンドウの中央下に暗い緑色で文字列を表示する場合は、上記のコードに以下のコードを追加します。

	wndSplash.showMessage( tr("がんばって起動しています"), Qt::AlignBottom | Qt::AlignHCenter, Qt::darkGreen );
	qApp->processEvents();

起動処理は初期表示ウィンドウ内で行われることが多いと思われます。
なので、初期表示ウィンドウクラスのコンストラクタにポインタを渡して、ウィンドウ内から上記のコードを呼び出すようにすることが多いようです。


PDF作成

Qtでは簡単にPDFを作成する機構が用意されています。
典型的な使い方としては以下のようにします。

   1: 
   2: #include <QPdfWriter>
   3: 
   4:   // PDFを作成
   5:   QPdfWriter pdfWriter( "ファイル名" );
   6: 
   7:   // レイアウトオブジェクト
   8:   QPageLayout pdfLayout;
   9: 
  10:   // 単位をポイントに設定
  11:   pdfLayout.setUnits( QPageLayout::Point );
  12:   
  13:   // 紙サイズ、余白を設定
  14:   pdfLayout.setPageSize( QPageSize(QPageSize::A4), QMarginsF(105.0, 40.0, 40.0, 20.0) );
  15:   
  16:   // 縦に設定
  17:   pdfLayout.setOrientation( QPageLayout::Portrait );
  18: 
  19:   // レイアウトオブジェクトをPDFに設置
  20:   pdfWriter.setPageLayout( pdfLayout );
  21:   
  22:   // DPIを取得する場合は以下のようにする
  23:   double dPixToPoints = (double)pdfWriter.resolution() / 72.0;
  24: 
  25:   // あとはペインタを通してPDFに書き込む
  26:   QPainter painter;
  27:   if ( painter.begin( &pdfWriter ) )
  28:   {
  29:     painter.drawText( QPoint(100, 100), "何か文字" );
  30: 
  31:     // 改ページ
  32:     pdfWriter.newPage();
  33:   }
  34: 
  35:   painter.end();

画像の印刷解像度(dpi)を設定するには

よく画像ファイルで見かける「解像度」ですが、あれは印刷解像度です。
すなわち、DPIとは紙上1インチに何ピクセルを詰め込むかの値です。

例として、1440 x 1440pix、72dpiの画像を印刷した場合、紙上のサイズは、
1440 / 72 inch = 508mmとなります。

この値をQImageオブジェクトに設定して保存するには以下のようにします。

   1: 
   2:   // ドット / メートルに変換(72dpiの場合)
   3:   int dpm = 72 / 0.0254;
   4: 
   5:   // 水平方向、垂直方向別個に指定可能
   6:   qimg.setDotsPerMeterX( dpm );
   7:   qimg.setDotsPerMeterY( dpm );
   8: 
   9:   // dpiをファイル内に保持できるフォーマットでないと設定できません
  10:   qimg.save( arrPath, "JPEG", -1 );

クリップボードを使うには

Qtにおけるクリップボードはえらく簡単です。以下のようにします。

  // クリップボードオブジェクトを取得
  auto clipboad = QApplication::clipboard();
  
  // テキストをクリップボードにコピー
  clipboad->setText( str );

set**の関数はsetText()のほかに
setImage()setPixmap()
setMimeData()があります。

取り出しはそれぞれtext()Image
pixmap()mimeData()
を使用します。


とりあえずダイアログを表示するには

「このプログラムについて」のように、とくにイベントが発生しないようなダイアログを表示したい場合は、デザイナで設計したUiを直接使いましょう。

   1:   QDialog dlg;
   2:   Ui::Dialog_about ui;
   3:   ui.setupUi( &dlg );
   4:   dlg.exec();

デスクトップのサイズを取得するには

現在のデスクトップのサイズを取得するには以下のようにします。

  QRect rcScreen = QApplication::desktop()->screenGeometry();

ウィンドウを常に前面に表示するには

モードレスダイアログなどのウィンドウを常に前面に表示したい場合は以下のようにします。

  m_pdlg->setWindowFlags( Qt::WindowStaysOnTopHint );

コマンド引数を取得するには

プログラム起動時のコマンド引数を取得するには以下のようにします。

  QStringList listArgs = QCoreApplication::arguments();

main()関数のargvと同様に、配列の最初の要素はプログラム名です。


アプリケーションのディレクトリを取得するには

プログラムに同梱するファイルを参照したり等々、何かとよく使うアプリケーションのディレクトリ取得は以下のようにします。

  QString strAppDir = QCoreApplication::applicationDirPath();

ツールボタンの排他的選択を設定するには

ビュー操作などでツールボタンの選択を排他的にしたい場合はアクショングループを設定します。

  // メンバ変数として宣言
  QActionGroup *m_pActionGroup;
  
  ////////////////
  m_pActionGroup = new QActionGroup( this );
  m_pActionGroup->addAction( action1 );
  m_pActionGroup->addAction( action2 );
  m_pActionGroup->setExclusive( true );

Qtのバージョンを取得するには

使用しているQtのバージョンを取得する関数はqVersion()です。
戻り値はconst char *で、「4.8.6」といった文字列が返ってきます。


アーカイブ