Pythonの変数のスコープとWidget

ローカル変数に格納したWidgeのインスタンスはスコープを外れるとなくなる
これはQGISのプラグイン開発時にふと違和感を感じたPythonの仕様?

関数initGuiの中でQDockWidgetのインスタンスをローカル変数「mainpanel」にセットして
画面に追加すると正しく表示されない

しかしクラスのメンバー変数にセットすると正しく表示される

本来はaddDockWidgetした時点でインスタンスは他で保たれるであろうから表示されないことはない気がするが・・・

正しく表示されない例

def initGui(self):
    mainpanel = MainPanelDockWidget()
    self.iface.addDockWidget(Qt.RightDockWidgetArea, mainpanel)
    self.dockwidget.show()

正しく表示される例

def initGui(self):
    self.dockwidget = MainPanelDockWidget()
    self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget)
    self.dockwidget.show()

QtデザイナでSplitterを配置

QDocWidget上にSplitterを配置

QWidgetを左右に配置

2つのQWidgetを選択して「ツールバー」の「水平にスプリッタの中に並べる」を選択

以上で2つのQWidgetがSplitterに配置される

Splitterが親のQDockWidget一杯に表示されるようにdockWidgetContentsを選択して「ツールバー」の「水平に並べる」ボタンをクリック

以上

QtデザイナでQDockWidgetをベースにレイアウトをデザインすると何も部品が置けない(2)

QDockWidgetにQWidgetが追加されないため、uiファイルを直接編集してQWidgetを追加。

編集前

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>DockWidget</class>
 <widget class="QDockWidget" name="DockWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="allowedAreas">
   <set>Qt::AllDockWidgetAreas</set>
  </property>
  <property name="windowTitle">
   <string>DockWidget</string>
  </property>
 </widget>
 <resources/>
 <connections/>
</ui>

編集後

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>DockWidget</class>
 <widget class="QDockWidget" name="DockWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="allowedAreas">
   <set>Qt::AllDockWidgetAreas</set>
  </property>
  <property name="windowTitle">
   <string>DockWidget</string>
  </property>

  <widget class="QWidget" name="dockWidgetContents">
  </widget>

 </widget>
 <resources/>
 <connections/>
</ui>

Qtデザイナで再度uiファイルを開くと正しくQWidgetが追加されている

カテゴリー: Qt

QtデザイナでQDockWidgetをベースにレイアウトをデザインすると何も部品が置けない(1)

Qtデザイナを起動してメニュー「ファイル」-「ファイルを新規作成」を選択し以下に従ってデザイナ画面を起動

本来DockWidget配下にQWidgetが表示され、その上に部品を配置することができる。

しかしDockWidget配下にQWidgetがどうしても追加されない。

カテゴリー: Qt

QGIS3+Eclipse+PyDevでデバッグ

環境

OS Windows10 64bit
QGIS QGIS3.4.4(OSGEO4W 32bit)
Eclipse 2018-12 64bit
Java Oracle JRE 10
PyDev 7.1.0.201902031515

QGISをインストール

OSGEO4W版のインストーラーを起動しC:\OSGEO4Wにインストール

QGISを起動

Eclipse

以下よりEclipseをダウンロード

https://www.eclipse.org/downloads/download.php?file=/oomph/epp/2018-12/R/eclipse-inst-win64.exe

ダウンロードしたeclipse-inst-win64を実行

起動すると以下のメッセージ表示

Eclipseのサイトより「Oracle JRE 10」をダウンロード

https://download.eclipse.org/oomph/jre/index-handler.php?vm=1_1_7_0_64_0&pn=Eclipse%20Installer&pu=http://wiki.eclipse.org/Eclipse_Installer&pi=http://download.eclipse.org/oomph/jre/128×128.png

ダウンロードした「jre-10.0.2_windows-x64_bin」を実行

インストールボタンをクリック

再度「eclipse-inst-win64」を実行

eclipse インストーラーが起動されたら「eclipse IDE for java developers」を選択

証明書の確認

PyDev

Eclipseを起動してHelpメニューの「Install New Software」

「Work With」の「Add」ボタンをクリック

NameにPyDev、Locationに「http://pydev.org/updates」を指定しAddボタンをクリック

PyDevをチェックしてNEXTボタンをクリック

Detaileボタンを押してPydevのインストール先を確認してから「Install Anyway」を実行

PyDevの設定

Eclipseを起動して「Window」→「Preferences」を選択

左のTreeでPyDev-Interpreters-Python Interpreterを選択

QGISが使用するPython.exeを指定するためにQGISを起動してPYTHONHOMEの値を確認

「Browse for pythonpypy exe」ボタンを押してNAMEには任意の名称(ここではpython37)、値には先ほど調べたPython.exeのフルパスを指定。

Librariesは自動でいくつかの参照先が指定されるが手動で不足分を指定

先ほどインストール先を確認したPyDevも指定

Packagesには警告らしき表示があるが無視

Forced Builtinsのタブを表示して「New」ボタンを押してqgisとPyQt5をそれぞれ登録

Environmentoタブを表示して以下の環境変数を設定

「Apply」ボタンを押して「Apply and Close」ボタンを押して設定を反映

設定内容が即反映されないので「Apply」ボタンを押したら暫く待つこと。

※設定が終了する前に画面を閉じると正しく設定が終了しない

デバッグの準備

外部TOOLにQGISを設定

メニュ「Run」-「External Tools Configurations」を指定して外部TOOLとしてQGISを設定

プロジェクトを作成

Eclipseの「New」メニューから-「Project」-「PyDev Project」を選択

以下に従ってプロジェクトの内容を設定しFinishボタンを押す

確認のためにQGISのPlugin Builder3でプラグインを作成して「C:\Users\ユーザー名\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins\」に配置

init.pyに以下を記述

import os,sys
sys.path.append("C:\\Users\\kernel\\.p2\\pool\\plugins\\org.python.pydev.core_7.1.0.201902031515\\pysrc")
import pydevd
pydevd.settrace()

sys.pathに追加しているのはPyDev

この記述はEclipseを使用しないときはエラーとなる

これを記述するとclassFactory関数でブレークする

デバッグ実行

ここからの操作は若干確信がないが、とりあえず正しく動作したので良しとして説明

プラグイン「Remote Debug」と「Plugin Reloader」を有効にするためにプラグインの設定で実験的プラグインも表示する

デバッグボタンを押す

「start pydev Server」ボタンをクリック

「外部TOOL QGISを起動」

iOS アプリをAdHocでインストール

Xcodeのバージョンが10.1になったのであらためてiOSアプリの作成からAdHocでインストールするまでをおさらい!

最初にXcodeでSingle View Appを作成

最近はXcodeが勝手に証明書関連を設定してくれるが、なぜかうまくいかなかったので手動で設定する

Apple DeveloperにログインしてProductionの証明書を確認

証明書はXcodeのPreferencesをクリックしてして表示される画面の左下+ボタンで作成可能

App IDを作成

DeviceにAdHocでインストールしてするデバイスを追加

AdHocで使用するProvisioning Profilesを作成

以上でçの作成は終了

XcodeのPreferencesからAppleIDの画面を表示して「Download Manual Profiles」ボタンを押してAdHoc用のProvisioning Profilesをダウンロード(していると思う・・・)

xcodeを開いてSigningのチェックを外しProvisioning Profilesに作成したAdHocを指定する

これからAdHoc用のコンパイルを開始するが、その前にProductメニューのDestinationをGeneric iOS Deviceに設定。この設定をしないとProductメニューのArciveが有効にならない。

ProductメニューのArciveを実行

「Distribute App」ボタンをクリック

AdHocを選択

optionを指定

証明書とProvisioning Profilesを指定

Exportボタンを押してipaファイルの出力先を指定。

iPhoneにインストール

iTunesを起動してiPhoneを接続

iPaをiTunesの左パネルの自分のデバイス上にドラッグしてインストール

ちなみにiTunes 12.7.3.64では正しくインストールできたが、12.8.2.3ではドラッグできなかった?

QgsVectorLayerのQgsCoordinateReferenceSystemを設定

投影情報を持っていないShapeファイルを読み込んで「QgsVectorLayer」を作成した後に投影情報を設定する

訂正

layer = QgsVectorLayer(Shapeファイルのフルパス, レイヤ名, "ogr")
crs = QgsCoordinateReferenceSystem.fromEpsgId(2451)
layer.setCrs(crs)
× crs = layer.crs()
× crs.createFromString('EPSG:2451')

QgsMessageBarを表示しない

CRSが未設定のレイヤを表示するとQgsMessageBarが表示される

「新しいレイヤの投影座標系」を「プロジェクトのCRSを使用」に設定してもこれは避けられない

QgisAppクラスのvalidateCrsを確認すると

void QgisApp::validateCrs( QgsCoordinateReferenceSystem &srs )
{
  static QString sAuthId = QString();
  QgsSettings mySettings;
  QString myDefaultProjectionOption = mySettings.value( QStringLiteral( "Projections/defaultBehavior" ), "prompt" ).toString();
  if ( myDefaultProjectionOption == QLatin1String( "prompt" ) )
  {
  省略
  }
  else if ( myDefaultProjectionOption == QLatin1String( "useProject" ) )
  {
    // XXX TODO: Change project to store selected CS as 'projectCRS' not 'selectedWkt'
    sAuthId = QgsProject::instance()->crs().authid();
    srs.createFromOgcWmsCrs( sAuthId );
    QgsDebugMsg( "Layer srs set from project: " + sAuthId );
    messageBar()->pushMessage( tr( "CRS was undefined" ), tr( "defaulting to project CRS %1 - %2" ).arg( sAuthId, srs.description() ), Qgis::Warning, messageTimeout() );
  }
  else ///Projections/defaultBehavior==useGlobal
  {
  省略
  }
}

「プロジェクトのCRSを使用」に設定するとかならず「messageBar()->pushMessage」が呼ばれてしまう。
フラグなどで対応することはできそうもない。

QgsMessageBarクラス参考

とりあえず以下のコードで表示される時間を1秒に設定

QSettings().setValue( "qgis/messageTimeout", 1 )
カテゴリー: QGIS

QgsFillSymbolの設定

ポリゴンのシンボルQgsFillSymbolの設定(構築)はQgsFillSymbolクラスのメソッドcreateSimpleにスタイルを渡して設定する。

内部の色、外周の色を設定する時は

QgsFillSymbol.createSimple({'color': '0,0,0,0','outline_color': '255,0,0,255'})

更に内部のパターンを設定する時は

QgsFillSymbol.createSimple({'color': '0,0,0,0','outline_color': '255,0,0,255','style' : 'diagonal_x'})

設定のキーはQgsSymbolLayer::createを参考

QgsSymbolLayer *QgsSimpleFillSymbolLayer::create( const QgsStringMap &props )
{
  QColor color = DEFAULT_SIMPLEFILL_COLOR;
  Qt::BrushStyle style = DEFAULT_SIMPLEFILL_STYLE;
  QColor strokeColor = DEFAULT_SIMPLEFILL_BORDERCOLOR;
  Qt::PenStyle strokeStyle = DEFAULT_SIMPLEFILL_BORDERSTYLE;
  double strokeWidth = DEFAULT_SIMPLEFILL_BORDERWIDTH;
  Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEFILL_JOINSTYLE;
  QPointF offset;

  if ( props.contains( QStringLiteral( "color" ) ) )
    color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )] );
  if ( props.contains( QStringLiteral( "style" ) ) )
    style = QgsSymbolLayerUtils::decodeBrushStyle( props[QStringLiteral( "style" )] );
  if ( props.contains( QStringLiteral( "color_border" ) ) )
  {
    //pre 2.5 projects used "color_border"
    strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color_border" )] );
  }
  else if ( props.contains( QStringLiteral( "outline_color" ) ) )
  {
    strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )] );
  }
  else if ( props.contains( QStringLiteral( "line_color" ) ) )
  {
    strokeColor = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "line_color" )] );
  }

  if ( props.contains( QStringLiteral( "style_border" ) ) )
  {
    //pre 2.5 projects used "style_border"
    strokeStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "style_border" )] );
  }
  else if ( props.contains( QStringLiteral( "outline_style" ) ) )
  {
    strokeStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "outline_style" )] );
  }
  else if ( props.contains( QStringLiteral( "line_style" ) ) )
  {
    strokeStyle = QgsSymbolLayerUtils::decodePenStyle( props[QStringLiteral( "line_style" )] );
  }
  if ( props.contains( QStringLiteral( "width_border" ) ) )
  {
    //pre 2.5 projects used "width_border"
    strokeWidth = props[QStringLiteral( "width_border" )].toDouble();
  }
  else if ( props.contains( QStringLiteral( "outline_width" ) ) )
  {
    strokeWidth = props[QStringLiteral( "outline_width" )].toDouble();
  }
  else if ( props.contains( QStringLiteral( "line_width" ) ) )
  {
    strokeWidth = props[QStringLiteral( "line_width" )].toDouble();
  }
  if ( props.contains( QStringLiteral( "offset" ) ) )
    offset = QgsSymbolLayerUtils::decodePoint( props[QStringLiteral( "offset" )] );
  if ( props.contains( QStringLiteral( "joinstyle" ) ) )
    penJoinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( props[QStringLiteral( "joinstyle" )] );

  QgsSimpleFillSymbolLayer *sl = new QgsSimpleFillSymbolLayer( color, style, strokeColor, strokeStyle, strokeWidth, penJoinStyle );
  sl->setOffset( offset );
  if ( props.contains( QStringLiteral( "border_width_unit" ) ) )
  {
    sl->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "border_width_unit" )] ) );
  }
  else if ( props.contains( QStringLiteral( "outline_width_unit" ) ) )
  {
    sl->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "outline_width_unit" )] ) );
  }
  else if ( props.contains( QStringLiteral( "line_width_unit" ) ) )
  {
    sl->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "line_width_unit" )] ) );
  }
  if ( props.contains( QStringLiteral( "offset_unit" ) ) )
    sl->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )] ) );

  if ( props.contains( QStringLiteral( "border_width_map_unit_scale" ) ) )
    sl->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "border_width_map_unit_scale" )] ) );
  if ( props.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
    sl->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_map_unit_scale" )] ) );

  sl->restoreOldDataDefinedProperties( props );

  return sl;
}

設定値はQgsSymbolLayerUtilsを参照

Qt::BrushStyle QgsSymbolLayerUtils::decodeBrushStyle( const QString &str )
{
  if ( str == QLatin1String( "solid" ) ) return Qt::SolidPattern;
  if ( str == QLatin1String( "horizontal" ) ) return Qt::HorPattern;
  if ( str == QLatin1String( "vertical" ) ) return Qt::VerPattern;
  if ( str == QLatin1String( "cross" ) ) return Qt::CrossPattern;
  if ( str == QLatin1String( "b_diagonal" ) ) return Qt::BDiagPattern;
  if ( str == QLatin1String( "f_diagonal" ) ) return Qt::FDiagPattern;
  if ( str == QLatin1String( "diagonal_x" ) ) return Qt::DiagCrossPattern;
  if ( str == QLatin1String( "dense1" ) ) return Qt::Dense1Pattern;
  if ( str == QLatin1String( "dense2" ) ) return Qt::Dense2Pattern;
  if ( str == QLatin1String( "dense3" ) ) return Qt::Dense3Pattern;
  if ( str == QLatin1String( "dense4" ) ) return Qt::Dense4Pattern;
  if ( str == QLatin1String( "dense5" ) ) return Qt::Dense5Pattern;
  if ( str == QLatin1String( "dense6" ) ) return Qt::Dense6Pattern;
  if ( str == QLatin1String( "dense7" ) ) return Qt::Dense7Pattern;
  if ( str == QLatin1String( "no" ) ) return Qt::NoBrush;
  return Qt::SolidPattern;
}

QString QgsSymbolLayerUtils::encodeSldBrushStyle( Qt::BrushStyle style )
{
  switch ( style )
  {
    case Qt::CrossPattern:
      return QStringLiteral( "cross" );
    case Qt::DiagCrossPattern:
      return QStringLiteral( "x" );

    /* The following names are taken from the presentation "GeoServer
     * Cartographic Rendering" by Andrea Aime at the FOSS4G 2010.
     * (see http://2010.foss4g.org/presentations/3588.pdf)
     */
    case Qt::HorPattern:
      return QStringLiteral( "horline" );
    case Qt::VerPattern:
      return QStringLiteral( "line" );
    case Qt::BDiagPattern:
      return QStringLiteral( "slash" );
    case Qt::FDiagPattern:
      return QStringLiteral( "backslash" );

    /* define the other names following the same pattern used above */
    case Qt::Dense1Pattern:
    case Qt::Dense2Pattern:
    case Qt::Dense3Pattern:
    case Qt::Dense4Pattern:
    case Qt::Dense5Pattern:
    case Qt::Dense6Pattern:
    case Qt::Dense7Pattern:
      return QStringLiteral( "brush://%1" ).arg( encodeBrushStyle( style ) );

    default:
      return QString();
  }
}

カテゴリー: QGIS