Windows用のバイナリもあるのだがなぜかうまくいかない?デバッグ用のdllしか用意されていない?ので自分でCMakeした方がよい。
拍子抜けするほど簡単。
installディレクトリだけ気を付ければ詰まらない。ビルドもすぐに終わる。
VC++から使用するときの設定
// https://docs.wxwidgets.org/3.0/overview_helloworld.html // プリプロセッサに以下二つを追加 // __WXMSW__ // WXUSINGDLL // サブシステムをWindowsに設定(WinMainで呼び出すので) // Windows (/SUBSYSTEM:WINDOWS) #ifndef WX_PRECOMP #include <wx/wx.h> #endif #include <wx/gdicmn.h> // wxPointに必要 #include <wx/frame.h> // wxFrameに必要 #pragma comment(lib,"wxbase32u.lib") #pragma comment(lib,"wxbase32u_net.lib") #pragma comment(lib,"wxbase32u_xml.lib") #pragma comment(lib,"wxmsw32u_adv.lib") #pragma comment(lib,"wxmsw32u_aui.lib") #pragma comment(lib,"wxmsw32u_core.lib") #pragma comment(lib,"wxmsw32u_gl.lib") #pragma comment(lib,"wxmsw32u_html.lib") #pragma comment(lib,"wxmsw32u_media.lib") #pragma comment(lib,"wxmsw32u_propgrid.lib") #pragma comment(lib,"wxmsw32u_qa.lib") #pragma comment(lib,"wxmsw32u_ribbon.lib") #pragma comment(lib,"wxmsw32u_richtext.lib") #pragma comment(lib,"wxmsw32u_stc.lib") #pragma comment(lib,"wxmsw32u_webview.lib") #pragma comment(lib,"wxmsw32u_xrc.lib") ///////////////////////////////////// ///////////////////////////////////// /////////////////////////////////////
// ウィンドウ作成 class MyFrame : public wxFrame { public: MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { } private: // イベント処理しないときはこれを入れない // wxDECLARE_EVENT_TABLE(); };
///////////////////////////////////// ///////////////////////////////////// /////////////////////////////////////
// wxWidgetsのアプリケーション作成 class MyApp : public wxApp { public: virtual bool OnInit() { MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340)); frame->Show(true); return true; } };
///////////////////////////////////// ///////////////////////////////////// /////////////////////////////////////
// WinMainをマクロで定義 wxIMPLEMENT_APP(MyApp);
コンパイルオプションと、ライブラリを切り分け、プリプロセッサの指定を変える方法。
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
DebugビルドとReleaseビルドで使用するライブラリを変える。
set( DEBUG_LIB_PATH C:/libraries/wxWidgets/debug/lib/vc_x64_dll) find_library( DEBUG_Lib NAMES wxbase32ud.lib PATHS ${DEBUG_LIB_PATH}) set( RELEASE_LIB_PATH C:/libraries/wxWidgets/release/lib/vc_x64_dll) find_library( RELEASE_Lib NAMES wxbase32u.lib PATHS ${RELEASE_LIB_PATH}) target_link_libraries(${MY_PROJECT_NAME} PRIVATE $<$<CONFIG:Debug>:${DEBUG_Lib}> $<$<CONFIG:Release>:${RELEASE_Lib}> )
set( RELEASE_def -D__RELEASE__) set( DEBUG_def -D__DEBUG__) target_compile_definitions( ${MY_PROJECT_NAME} PRIVATE $<$<CONFIG:Release>:${RELEASE_def}> $<$<CONFIG:Debug>:${DEBUG_def}> )
デフォルトでリリースビルドにする。
ただしこの設定は、Visual StudioのGUIでslnを開いた場合には反映されない。
if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif()
まずは基本。以下で、MySolutionというソリューションを作成できる。””で囲まないことに注意。
しかし、setで変数を定義して、${}で変数指定する方が一般的らしい。
例として、以下のディレクトリ構造でCMakeLists.txtを書いてみる。
D:.
│
└─src
CMakeLists.txt
function.cpp
main.cpp
source.hpp
# CMakeのバージョンを設定 今自分が使っているものを指定している # 必須要件なので、数字は小さい方がいい。 cmake_minimum_required(VERSION 3.25) ############################################# ############################################# # ソリューション名を設定 set(MY_SOLUTION_NAME "MySolution") #プロジェクト名を設定 set(MY_PROJECT_NAME "MyProject") # 出力ファイル名を設定 set(MY_OUTPUT_NAME "myout") ############################################# ############################################# # ソリューションを作成 # プロジェクト名と使用する言語を設定 project(${MY_SOLUTION_NAME} CXX) ############################################# ############################################# # main.cpp function.cppからプロジェクト作成 add_executable(${MY_PROJECT_NAME} main.cpp function.cpp) ############################################# #############################################
# 出力名を"myout.exe"に設定 set_target_properties(${MY_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${MY_OUTPUT_NAME})
includeディレクトリ、ライブラリディレクトリ、ライブラリファイルを追加する。add_executableとの順番が重要になる。
# CMakeのバージョンを設定 今自分が使っているものを指定している # 必須要件なので、数字は小さい方がいい。 cmake_minimum_required(VERSION 3.25) ############################################# ############################################# # ソリューション名を設定 set(MY_SOLUTION_NAME "MySolution") #プロジェクト名を設定 set(MY_PROJECT_NAME "MyProject") # 出力ファイル名を設定 set(MY_OUTPUT_NAME "myout") ############################################# ############################################# # ソリューションを作成 # プロジェクト名と使用する言語を設定 project(${MY_SOLUTION_NAME} CXX) ############################################# ############################################# # ライブラリディレクトリ追加 # 注:add_executableの前でなければならない link_directories(path/to/library/directory) # プロジェクトを作成 # out.exeという実行ファイルをmain.cppから作成 add_executable(${MY_PROJECT_NAME} main.cpp function.cpp) # includeディレクトリ追加 # 注:add_executableの後でなければいけない target_include_directories(${MY_PROJECT_NAME} PRIVATE path/to/include/directory) # ライブラリ追加 target_link_libraries(${MY_PROJECT_NAME} mylib1.lib mylib2.lib) ############################################# ############################################# set_target_properties(${MY_PROJECT_NAME} PROPERTIES OUTPUT_NAME ${MY_OUTPUT_NAME})
projectGeneratorで作成したソリューションを(いうまでもないがディレクトリごと)別のパスへ移動すると、エラーとなる。例えば作成したmyTestディレクトリのパスを変える。
before
・D:\myDevelop\of-test\myTest\myTest.sln
after
・D:\myDevelop\of-test\test\myTest\myTest.sln
前提として、以下のパスにOpenFrameworksを配置している。
before:
after:
ただし場所によっては/区切りなので、それにも対応しておく。
before:
after:
以下、どうしても絶対パスを使いたい場合の注意。
修正前:
修正後:

まず、フルパスに置換するために以下を置換する
before:
after:
before:
after:
基本的には全て絶対パスでも動くのだが、<ItemGroup>の部分だけは相対パスでなければならない。
導入は非常に簡単で、ダウンロードするだけ。CMake不要。さらに外部ツールのProjectGenerator(インストール不要)を使ってプロジェクトを作成するので間違いもない。
非常に簡単。
OpenFrameworksの公式サイトへ行き、visual studio(2017-2022)をダウンロード、解凍する。
https://openframeworks.cc/ja/download/
適当なフォルダへ展開できたら、以下のディレクトリ内にある、emptyExample.slnを開く。
コピーする場合、of_v0.11.2_vs2017_releaseフォルダごとコピーしなければいけないことに注意
ofApp.cppに入っているofApp::draw()の中にOpenGLの描画関数を入れてみる。
#include "ofApp.h" //-------------------------------------------------------------- void ofApp::setup(){ } //-------------------------------------------------------------- void ofApp::update(){ }
//-------------------------------------------------------------- void ofApp::draw(){ glClearColor(1, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glFlush(); }
//-------------------------------------------------------------- void ofApp::keyPressed(int key){ } //-------------------------------------------------------------- void ofApp::keyReleased(int key){ }
#pragma once #include "ofMain.h" // of-test\of_v0.11.2_vs2017_release\addons\ofxGui\src // GUI部品 #include <ofxGui.h> class ofApp : public ofBaseApp{ // GUI部品 ofxGui.h ofxPanel gui; ofxFloatSlider angle; // スライダー ofxButton button; // ボタン ofxToggle toggle; // チェックボックス ofxTextField text; // テキストボックス // ボタンのイベントリスナー void buttonClicked() { cout << "ボタンが押された" << endl; } public: void setup(); void update(); void draw(); void keyPressed(int key); // ... };
#include "ofApp.h"
//-------------------------------------------------------------- void ofApp::setup(){ // GUI部品の作成・登録 gui.setup(); gui.add(angle.setup("angle", 0, 10, 300)); // スライダー作成 gui.add(button.setup("push", 140, 50)); // ボタン作成 gui.add(toggle.setup("toggle",false, 140, 30)); // チェックボックス作成 gui.add(text.setup("text-field", "default text"));// テキスト入力 // ボタンにイベントリスナーを登録 button.addListener(this, &ofApp::buttonClicked); }
//-------------------------------------------------------------- void ofApp::draw(){ glClearColor(1, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); //////////////////////////////////////////// // OpenGL 1 で 描画開始 int width = ofGetWindowWidth(); int height = ofGetWindowHeight(); glViewport(0, 0, width, height); glOrtho(-1, 1, -1, 1, -1, 1); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glRotatef(angle.getParameter().cast<float>().get(), 0, 0, 1); glBegin(GL_QUADS); glColor3d(1, 0, 0); glVertex2d(-0.7, -0.7); glColor3d(0, 1, 0); glVertex2d(-0.7, 0.7); glColor3d(0, 0, 1); glVertex2d(0.7, 0.7); glColor3d(1, 1, 1); glVertex2d(0.7, -0.7); glEnd(); glPopMatrix(); //////////////////////////////////////////// // UIを表示 glMatrixMode(GL_PROJECTION); glPopMatrix(); gui.draw(); glFlush(); }
上記だけだとGUIパーツ関係でリンクエラーになるので各.cppファイルをプロジェクトへ追加する。
調べるとVisual Studioのプラグインを使用する例がたくさん出てくるが、どうも現在はProjectGeneratorという外部ツールでソリューションを作る方式に変わっている気がする。
以下にProjectGenerator.exeがあるのでそれを起動する。
of_v0.11.2_vs2017_release\projectGenerator\projectGenerator.exe

Success!と言われたら出力したソリューションを叩くかOpen in IDEでプロジェクトを開ける。
あとは最初と同じコードで動く。
fn main() {
let source:&str = r#"<!DOCTYPE html> <html lang="ja"> <head> <title> HTML in the code </title> </head> <body> <div id="mymain"> <p> first line </p> <p> second <br/> line </p> <p> third line </p> <img src="data.jpg" /> </div> <div id="myfooter"> <p>copyright</p> </div> </body> </html "#;
//////////////////////////
// HTMLの解析
let myparse:scraper::Html = scraper::Html::parse_document(&source);
let selector:scraper::Selector = scraper::Selector::parse("*").unwrap();
let parsed:scraper::ElementRef = myparse.select(&selector).next().unwrap();
println!("*************************");
traverse_element(&parsed,1);
}
/// @brief 解析済みのHTMLを再帰的に走査して内容を表示 /// @param [in] elementref 解析済みのエレメント /// @param [in] depth 再帰の階層 /// @return なし fn traverse_element(elementref: &scraper::ElementRef, depth: usize) { let indent:String = " ".repeat(depth*3);// 階層に合わせて左側に挿入するスペース let element:&scraper::node::Element = elementref.value(); let tag_name:&str = element.name(); print!("{}",depth); // 階層の表示 print!("{} {}",indent,tag_name); // タグ名表示 // 属性取得・保存 for attr in element.attrs(){ let attr_name =&attr.0.to_string(); let attr_value =&attr.1.to_string(); print!(" {} = {}", &attr_name, &attr_value ); } println!(""); // 子要素を再帰的に辿る for child in elementref.children() { if let Some(child_element) = child.value().as_element() { // タグの場合 // 子要素を走査 let c_elem_ref:scraper::ElementRef = scraper::ElementRef::wrap(child).unwrap(); traverse_element(&c_elem_ref, depth + 1); } else if let Some(text) = child.value().as_text() { // コンテンツの場合 let contents:&str = text.trim(); if !contents.is_empty() { print!("{}",depth); // コンテンツを表示 println!("[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]", contents); } } } }
1 html lang = ja
2 head
3 title
3[[[[[[[[[[[[[[[[[[HTML in the code]]]]]]]]]]]]]]]]]]]]]
2 body
3 div id = mymain
4 p
4[[[[[[[[[[[[[[[[[[first line]]]]]]]]]]]]]]]]]]]]]
4 p
4[[[[[[[[[[[[[[[[[[second]]]]]]]]]]]]]]]]]]]]]
5 br
4[[[[[[[[[[[[[[[[[[line]]]]]]]]]]]]]]]]]]]]]
4 p
4[[[[[[[[[[[[[[[[[[third
line]]]]]]]]]]]]]]]]]]]]]
4 img src = data.jpg
3 div id = myfooter
4 p
4[[[[[[[[[[[[[[[[[[copyright]]]]]]]]]]]]]]]]]]]]]
IntelliJ IDEAでJSoupを使ってみる。
全くやったことがないので導入だけのメモになる。
コードは以下の通り。
import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; fun main(args: Array<String>) { val url = "https://suzulang.com/" val doc = Jsoup.connect(url).get(); println(doc.title()); // タイトル取得 // divの内容をリストで取得 val divs = doc.select("div"); for(div in divs){ // div に子要素があればその内容をループ if( div.children().size > 0 ){ // pの一覧を取得 val paragraphs = div.children().select("p"); for(p in paragraphs){ println(p.text()); // pの内容を表示 } } } }
以下からダウンロード

展開したら、[File]→[Project Structure...]を選択
Dependenciesの中の+をクリックし、JARs or Directories...を選択
jsoup-1.15.4.jarファイルへのフルパスを指定。ディレクトリまでしか指定しないとjarファイルが表示されないので入力欄にファイル名まで全部入力するといい。
lxmlを使うとデータをツリー構造に格納してくれる。
import lxml.html # HTMLのテキスト text = """<html> <head><title>タイトル</title> <body> <p> hello world </p> <p> 二行目 </p> <div> 子要素 </div> </body> </html> """ ret = lxml.html.fromstring( text ) for itr in ret: # forでイテレーションする print(itr.tag) # タグへアクセス if len(list(itr)): # 子要素があるかどうかはlistの長さを調べる print("{") for i in itr: print(i.tag ,"[" , i.text , "]" ) print("}")
lxml.html.parseはURLを渡せるのだが、
どうやらHTTPSに対応していないらしい。
urllib.requestを使ってHTMLを取得し、それをfromstringへ入力する。
# lxmlはhttpsに対応していない。 # html.parse( /*ここに入れていいのはhttpのURLだけ*/ ) # urllib.request.urlopenを使ってhttpsからテキストを取得してそれを入力する # from urllib import urlopen # Python2だとurllib2らしい import urllib.request urldata = urllib.request.urlopen('https://suzulang.com/') text = urldata.read() print( text )
HTMLParserでHTMLをパースする。
HTMLParserクラスは、このクラスを継承して使用する。
HTMLParser.feedを呼び出すと、タグなどが見つかった際にオーバーライドしたhandle_starttagメソッドが呼ばれるので、その度に必要な処理を記述する。
注意
公式ドキュメント
https://docs.python.org/3/library/html.parser.html
にあるコードだとHTML内に改行が見つかるたびにhandle_dataが呼び出されてしまうので、\n単体が見つかった場合は何もしないように処理を追加。
from html.parser import HTMLParser ##################################### # HTMLのテキスト text = """<html> <body> <p> hello world </p> </body> </html> """
##################################### #https://docs.python.org/3/library/html.parser.html # HTMLParserを継承したMyHTMLParserを作成 class MyHTMLParser(HTMLParser): # HTMLParser.feed を呼び出すと、以下の各関数がパース中に呼び出される def handle_starttag(self, tag, attrs): print("Encountered a start tag:", tag) def handle_endtag(self, tag): print("Encountered an end tag :", tag) def handle_data(self, data): # タグの後の改行でもhandle_dataが呼び出されてしまうため # 改行単体の時はひとまず抜ける if data == '\n': return print("Encountered some data :", data)
##################################### # パース処理 ps = MyHTMLParser() # パーサー作成 ps.feed(text) # パース実行
OpenGLのウィンドウ生成。
[package]
name = "testglutin"
version = "0.1.0"
edition = "2021"
[dependencies]
glutin = "0.26.0"
gl="0.14.0"
fn main() { let event_loop = glutin::event_loop::EventLoop::new(); let window = glutin::window::WindowBuilder::new().with_title("Rust glutin OpenGL");
// GLのコンテキストを作成 // この gl_context は ContextBuilder<NotCurrent,Window> 型 let gl_context = glutin::ContextBuilder::new() .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 3))) .build_windowed(window, &event_loop) .expect("Cannot create context"); // Rustにはシャドーイングがあるので、同じ名前の別変数を同じスコープ内に定義できる。 // この gl_context は ContextBuilder<PossibleCurrent,Window> 型 // 以降、gl_currentは以前の型の意味で用いることはできない let gl_context = unsafe { gl_context .make_current() .expect("Failed to make context current") };
// OpenGLの各関数を初期化 // これでgl::Viewportをはじめとする各関数の関数ポインタにアドレスが設定され、呼び出せるようになる。 gl::load_with(|symbol| gl_context.get_proc_address(symbol) as *const _); // event_loopを開始する event_loop.run(move |event, _, control_flow| { // Pollを指定するとループが走り続ける // Waitを指定するとイベントが発生したときだけループが動く。 *control_flow = glutin::event_loop::ControlFlow::Wait; match event { glutin::event::Event::WindowEvent { event, .. } => match event {
//////////////////////////////////////////////////////////////////// // ウィンドウを閉じる glutin::event::WindowEvent::CloseRequested => { // ウィンドウが閉じられた場合、event_loopを停止する *control_flow = glutin::event_loop::ControlFlow::Exit; },
//////////////////////////////////////////////////////////////////// // ウィンドウのサイズを変更 glutin::event::WindowEvent::Resized(new_size) => { // ビューポート再設定 unsafe { gl::Viewport(0, 0, new_size.width as i32, new_size.height as i32); } },
//////////////////////////////////////////////////////////////////// _ => (), }, _ => (), }
// 描画 unsafe { gl::Clear(gl::COLOR_BUFFER_BIT); gl::ClearColor(0.3, 0.3, 0.5, 1.0); } // スワップバッファ gl_context.swap_buffers().unwrap();
}); }