QtQuickの日本語クロスワード

頭蓋骨と骨、KDPV







暇なときにプロトタイプを作成するのが好きです。 これにより、新しいことを学ぶことができます。 このプロトタイプは、リソースhttp://www.nonograms.ru/のクライアントであり、その開発者はCast Iron K.A. / KyberPrizrak /です。 すべてのコードはGiHubで入手できます。 C ++側では、ギャラリーモデルであるHTMLを使用します。 QtQuick視覚化の側面。







今回、私はそれを拾うことにしました:









カットの下で考慮されます:









スクリーンショット

ギャラリー

メニュー







Qt WebKitなしで行う



このサイトでは、クロスワードパズルをマトリックス形式で提供しています。







var d=[[571,955,325,492], [6,53,49,55], [47,18,55,65], ...]]
      
      





さらにJSスクリプトはクロスワードhtmlコードを作成します。 WebKitモジュールは非推奨としてマークされています。 代わりに、Chromeプロジェクトに基づいたWeb Engineモジュールを使用することを提案します。







わずかな失望がすぐにあります。 Web Engineには、ページ上のDOMを操作するためのAPIがありません。 HTMLコードを解析するには、サードパーティのツール( C ++およびGumboのParsim HTML )を使用する必要がありました。

しかし、ページをロードし、必要なHTMLをレンダリングして取得できます。







 QString getHtml(const QUrl& url) { QWebEnginePage page; QEventLoop loop; QObject::connect(&page, &QWebEnginePage::loadFinished, &loop, &QEventLoop::quit); page.load(url); loop.exec(); QTimer::singleShot(1000, &loop, &QEventLoop::quit); QString html; page.toHtml([&html, &loop](const QString& data){ html = data; loop.quit(); }); loop.exec(); return html; }
      
      





QTimer :: singleShotは、ページが終了するのを待つためにここで使用されます。 toHtmlメソッド非同期で、入力パラメーターとしてコールバック関数を取り、結果を取得します。







クロスワードパズルの作成



クロスワードパズルプレゼンテーション

Crosswordは、できるだけ多くの列と行を表示することにしました。 上部のサイズ3の10列は赤で囲まれ、サイズ3の10行は左に囲まれています。次に、これらの値に対してコードが処理されます。







クロスワードパズルは、いくつかの方法で実行できます。









最後のオプションを選択しました。







完全なコード
 import QtQuick 2.5 import Qt.labs.controls 1.0 Item { clip:true property int margin: 20 property int fontSize: 12 property int ceilSize: 20; property int incCeilSize: ceilSize + 1 property color borderColor: "#424242" property int rows: 0; property int rowSize: 0; property int column: 0; property int columnSize: 0; implicitHeight : crossGrid.height+margin*2 implicitWidth : crossGrid.width+margin*2 function loadFromNonogramsOrg(url) { console.log("Load:"+url); crossword.formNanogramsOrg(url); } function showOnlyNaturalNumber(val) { return val > 0 ? val: " "; } function drawCrossword(){ var csize = crossword.size; if(csize.column() === 0 || csize.rows() === 0){ return; } console.log(csize.column() + "x" + csize.rows()); hRepeater.model = 0; rRepeater.model = 0; rowSize = crossword.rowSize(); columnSize = crossword.columnSize(); rows = csize.rows(); column = csize.column(); hRepeater.model = crossword.columnSize()*csize.column(); rRepeater.model = crossword.rowSize()*csize.rows(); bgImg.visible = true; } Image{ id: bgImg asynchronous: true visible: false height: parent.height width: parent.width source:"qrc:/wall-paper.jpg" } Grid { id: crossGrid anchors.centerIn: parent columns: 2 spacing: 2 rowSpacing: 0 columnSpacing: 0 Rectangle{ id:topLeftItm width: rowSize * ceilSize height:columnSize * ceilSize border.width: 1 border.color: borderColor color: "transparent" } Grid { id: cGrid rows: columnSize columns: column Repeater { id: hRepeater model: 0 Item { width: ceilSize; height: ceilSize property int rw : Math.floor(index/column) property int cn : Math.floor(index%column) property int prw: rw+1 property int pcm: cn+1 Rectangle{ height: (prw % 5 == 0) || (prw == columnSize) ? ceilSize : incCeilSize width: (pcm % 5 == 0) ? ceilSize : incCeilSize color: "transparent" border.width: 1 border.color: borderColor Text { anchors.centerIn: parent text:showOnlyNaturalNumber( crossword.columnValue(cn,rw)); font{ family: mandarinFont.name pixelSize: fontSize } } } } } } Grid { id: rGrid rows: rows columns: rowSize Repeater { id: rRepeater model: 0 Item { width: ceilSize; height: ceilSize property int rw : Math.floor(index/rowSize) property int cn : Math.floor(index%rowSize) property int prw: rw+1 property int pcn: cn+1 Rectangle{ height: prw % 5 == 0 ? ceilSize : incCeilSize width: (pcn % 5 == 0) || (pcn == rowSize) ? ceilSize : incCeilSize color: "transparent" border.width: 1 border.color: borderColor Text { anchors.centerIn: parent text:showOnlyNaturalNumber( crossword.rowValue(rw,cn)); font{ family: mandarinFont.name pixelSize: fontSize } } } } } } Rectangle{ id: playingField width: column * ceilSize height:rows * ceilSize border.width: 1 border.color: borderColor color: "transparent" Grid{ rows: rows columns:column Repeater { id: bRepeater model: rows * column Item { id: ceilItm width: ceilSize; height: ceilSize property int rw : Math.floor(index/column) property int cn : Math.floor(index%column) state: "default" Rectangle{ id: itmRec height: (rw+1) % 5 == 0 ? ceilSize : incCeilSize width: (cn+1) % 5 == 0 ? ceilSize : incCeilSize color: "transparent" border.width: 1 border.color: borderColor } Text{ id: itmTxt visible:false height: parent.height width: parent.width font.pixelSize: ceilSize horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text:"+" rotation:45 } MouseArea { anchors.fill: parent onClicked: { if(parent.state == "default"){ parent.state = "SHADED"; }else if(parent.state == "SHADED"){ parent.state = "CLEAR"; }else{ parent.state = "default"; } } } states: [ State{ name:"SHADED" PropertyChanges { target: itmRec; color: "black"; } PropertyChanges { target: itmTxt; visible: false; } }, State{ name:"CLEAR" PropertyChanges { target: itmRec; color: "transparent"; } PropertyChanges { target: itmTxt; visible: true; } } ] } } } } } Text{ visible: bgImg.visible anchors{ right: parent.right rightMargin: 10 bottom: parent.bottom } text:qsTr("Source: ")+"www.nonograms.ru" font{ family: hanZiFont.name pixelSize: 12 } } Connections { target: crossword onLoaded: { drawCrossword(); } } }
      
      





基本はItemで表され、そのサイズはcrossGridのサイズとインデントのサイズ( margin )から計算されます







 Item { clip:true implicitHeight : crossGrid.height+margin*2 implicitWidth : crossGrid.width+margin*2 /* ... */ Image{ id: bgImg asynchronous: true visible: false height: parent.height width: parent.width source:"qrc:/wall-paper.jpg" } Grid { id: crossGrid anchors.centerIn: parent columns: 2 spacing: 2 /* ... */ } }
      
      





CrossGrid要素







crossGrid







 Grid { id: crossGrid anchors.centerIn: parent columns: 2 spacing: 2 rowSpacing: 16 columnSpacing: 16 Rectangle{ id:topLeftItm color: "transparent" border.width: 1 border.color: borderColor /* ... */ } Grid { id: cGrid /* ... */ } Grid { id: rGrid /* ... */ } Rectangle{ id: playingField /* ... */ } }
      
      





topLeftItmの四角形の塗りつぶしスペース。 cGridrGridは、数字でグリッドを記述します。 クロスワードパズルを解決するためのplayingFieldフィールド。







メッシング



このように書く場合:







 Grid { id: cGrid rows: columnSize columns: column Repeater { id: hRepeater /* ... */ Item { width: ceilSize; height: ceilSize Rectangle{ height: ceilSize width: ceilSize color: "transparent" border.width: 1 border.color: borderColor Text { anchors.centerIn: parent text: index font{ family: mandarinFont.name pixelSize: fontSize } } } } } }
      
      





その後、行が2倍になります







ラインダブリング







行の二重化を削除するには、サイズがItemおよびRectangleのトリックを使用します。 アイテムのサイズは固定されているため、Repeater( Repeater )ではすべての要素が正確に配置されます。 二重線の必要性に応じて、 長方形は広く、高さが1つ大きくなります。







 Repeater { id: hRepeater model: 0 Item { width: ceilSize; height: ceilSize property int rw : Math.floor(index/column) property int cn : Math.floor(index%column) property int prw: rw+1 property int pcm: cn+1 Rectangle{ height: (prw % 5 == 0) || (prw == columnSize) ? ceilSize : incCeilSize width: (pcm % 5 == 0) ? ceilSize : incCeilSize color: "transparent" border.width: 1 border.color: borderColor Text { anchors.centerIn: parent text:showOnlyNaturalNumber( crossword.columnValue(cn,rw)); font{ family: mandarinFont.name pixelSize: fontSize } } } } }
      
      





ここでは、インデックスに基づいて、行( rw )と列( cn )が計算され、1ずつ増加し、5で割った余りが取られます。 5セルごとにRectangleとItemの幅または高さが同じであるため、線が2倍になります。







クロスワードフィールド



フィールドから、グリッドとマウスクリック処理が必要です。 メッシュセルの状態を紹介します。









非アクティブ状態から開始し、次の順序でマウスをクリックして変更します

状態グラフ







セル描画コード:







 Item { id: ceilItm width: ceilSize; height: ceilSize property int rw : Math.floor(index/column) property int cn : Math.floor(index%column) state: "default" Rectangle{ id: itmRec height: (rw+1) % 5 == 0 ? ceilSize : incCeilSize width: (cn+1) % 5 == 0 ? ceilSize : incCeilSize color: "transparent" border.width: 1 border.color: borderColor } Text{ id: itmTxt visible:false height: parent.height width: parent.width font.pixelSize: ceilSize horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter text:"+" rotation:45 } MouseArea { anchors.fill: parent onClicked: { if(parent.state == "default"){ parent.state = "SHADED"; }else if(parent.state == "SHADED"){ parent.state = "CLEAR"; }else{ parent.state = "default"; } } } states: [ State{ name:"SHADED" PropertyChanges { target: itmRec; color: "black"; } PropertyChanges { target: itmTxt; visible: false; } }, State{ name:"CLEAR" PropertyChanges { target: itmRec; color: "transparent"; } PropertyChanges { target: itmTxt; visible: true; } } ] }
      
      





セルに十字を追加するitmTxt要素。空としてマークされたセルを表示します。 ここで、私は州を通して様々な州を説明する機会を使っています

MouseAreaが移行します。 それがすべてが始まった理由です。 計算(グリッド座標へのマウス座標の変換)、手動の再描画はありません。








All Articles