<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Korea Tcl/Tk Community</title>
    <link>https://ihmin.tistory.com/</link>
    <description>Korea Tcl/Tk Community</description>
    <language>ko</language>
    <pubDate>Thu, 21 May 2026 13:47:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>티클러</managingEditor>
    <image>
      <title>Korea Tcl/Tk Community</title>
      <url>https://tistory1.daumcdn.net/tistory/6955869/attach/cfd7f48690134f18a3abc4c5ab5ffced</url>
      <link>https://ihmin.tistory.com</link>
    </image>
    <item>
      <title>bgexec 3.5</title>
      <link>https://ihmin.tistory.com/724</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://wiki.tcl-lang.org/page/Enhanced+Standalone+Bgexec+for+Unix+and+Windows&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wiki.tcl-lang.org/page/Enhanced+Standalone+Bgexec+for+Unix+and+Windows&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BLT의 bgexec를 critical 로 구현한 패키지로, 하나 이상의 프로세스를 포그라운드 또는 백그라운드로 실행하고, 표준 출력(stdout)과 표준 에러(stderr)를 Tcl 변수나 콜백 함수로 받을수 있는 확장 패키지입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/beN4Ej/dJMcacbV9NN/w5MrEPph1TFwIRBKPZ0AFk/bgexec3-5.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;bgexec3-5.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.31MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/724</guid>
      <comments>https://ihmin.tistory.com/724#entry724comment</comments>
      <pubDate>Wed, 6 May 2026 15:40:47 +0900</pubDate>
    </item>
    <item>
      <title>날씨 정보 MCP 서버</title>
      <link>https://ihmin.tistory.com/723</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;FastMCP로 구현함..&lt;/p&gt;
&lt;pre id=&quot;code_1777433963842&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from mcp.server.fastmcp import FastMCP
import httpx
from datetime import datetime
from geopy.geocoders import Nominatim

# FastMCP 서버 초기화
mcp = FastMCP(&quot;Weather Server&quot;)

def get_weather_description(code: int) -&amp;gt; str:
    &quot;&quot;&quot;WMO 날씨 코드를 한글 설명으로 변환&quot;&quot;&quot;
    weather_codes = {
        0: &quot;맑음&quot;,
        1: &quot;대체로 맑음&quot;,
        2: &quot;부분적으로 흐림&quot;,
        3: &quot;흐림&quot;,
        45: &quot;안개&quot;,
        48: &quot;서리 안개&quot;,
        51: &quot;가벼운 이슬비&quot;,
        53: &quot;보통 이슬비&quot;,
        55: &quot;강한 이슬비&quot;,
        61: &quot;약한 비&quot;,
        63: &quot;보통 비&quot;,
        65: &quot;강한 비&quot;,
        71: &quot;약한 눈&quot;,
        73: &quot;보통 눈&quot;,
        75: &quot;강한 눈&quot;,
        77: &quot;진눈깨비&quot;,
        80: &quot;약한 소나기&quot;,
        81: &quot;보통 소나기&quot;,
        82: &quot;강한 소나기&quot;,
        85: &quot;약한 눈 소나기&quot;,
        86: &quot;강한 눈 소나기&quot;,
        95: &quot;뇌우&quot;,
        96: &quot;약한 우박을 동반한 뇌우&quot;,
        99: &quot;강한 우박을 동반한 뇌우&quot;,
    }
    return weather_codes.get(code, f&quot;알 수 없는 날씨 (코드: {code})&quot;)


@mcp.tool()
async def get_weather(region: str) -&amp;gt; str:
    &quot;&quot;&quot;
    주소로 검색하여 현재 날씨 정보를 가져옵니다.  (예: 서울특별시 강남구 역삼동)

    Args:
        region: 주소

    Returns:
        날씨 정보 문자열
    &quot;&quot;&quot;
    geolocator = Nominatim(user_agent=&quot;SouthKorea&quot;)
    location = geolocator.geocode(region)

    if location:
        print(f&quot;위도: {location.latitude}, 경도: {location.longitude}&quot;)
    else:
        return f&quot;'{region}' 주소를 찾을수 없습니다.&quot;

    try:
        # Open-Meteo API 사용 (무료, API 키 불필요)
        url = &quot;https://api.open-meteo.com/v1/forecast&quot;
        params = {
            &quot;latitude&quot;: location.latitude,
            &quot;longitude&quot;: location.longitude,
            &quot;current&quot;: &quot;temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m&quot;,
            &quot;timezone&quot;: &quot;Asia/Seoul&quot;
        }

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            data = response.json()

        current = data[&quot;current&quot;]
        temp = current[&quot;temperature_2m&quot;]
        humidity = current[&quot;relative_humidity_2m&quot;]
        wind_speed = current[&quot;wind_speed_10m&quot;]
        weather_code = current[&quot;weather_code&quot;]

        weather_description = get_weather_description(weather_code)

        result = f&quot;&quot;&quot;
{location} 날씨 정보
━━━━━━━━━━━━━━━━━━━━
온도: {temp}&amp;deg;C
습도: {humidity}%
풍속: {wind_speed} km/h
날씨: {weather_description}
━━━━━━━━━━━━━━━━━━━━
조회 시간: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
        &quot;&quot;&quot;

        return result.strip()

    except Exception as e:
        return f&quot;날씨 정보를 가져오는 중 오류가 발생했습니다: {str(e)}&quot;

def main():
    mcp.run()

if __name__ == &quot;__main__&quot;:
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cI82fe/dJMcaakNXTW/J9wpkBb1G7k5YxMFe6hDM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cI82fe/dJMcaakNXTW/J9wpkBb1G7k5YxMFe6hDM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cI82fe/dJMcaakNXTW/J9wpkBb1G7k5YxMFe6hDM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcI82fe%2FdJMcaakNXTW%2FJ9wpkBb1G7k5YxMFe6hDM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;709&quot; height=&quot;336&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>fastmcp</category>
      <category>MCP</category>
      <category>weather</category>
      <category>날씨</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/723</guid>
      <comments>https://ihmin.tistory.com/723#entry723comment</comments>
      <pubDate>Wed, 29 Apr 2026 12:43:29 +0900</pubDate>
    </item>
    <item>
      <title>Tohil</title>
      <link>https://ihmin.tistory.com/722</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://github.com/flightaware/tohil&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/flightaware/tohil&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;Tohil&lt;/span&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;237&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bulJ1Z/dJMcadIxRLT/6RtOBtm02y6cb4q57R8v6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bulJ1Z/dJMcadIxRLT/6RtOBtm02y6cb4q57R8v6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bulJ1Z/dJMcadIxRLT/6RtOBtm02y6cb4q57R8v6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbulJ1Z%2FdJMcadIxRLT%2F6RtOBtm02y6cb4q57R8v6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;156&quot; height=&quot;158&quot; data-origin-width=&quot;237&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
은 파이썬과 TCL 사이의 통합을 제공하는 것을 목표로 합니다.&lt;/div&gt;
&lt;div&gt;Tohil은 파이썬 확장인 동시에 TCL 확장이기도 하며, Tcl 8.6 이상 및 Python 3.6 이상 버전에서 Tcl과 파이썬 간의 유연한 양방향 호출을 가능하게 합니다.&lt;/div&gt;
&lt;div&gt;Tohil은 오픈 소스 소프트웨어이며, 허용적인 '3-clause BSD 라이선스'(LICENSE.txt 참조)에 따라 영리 목적이나 재배포를 포함하여 무료로 사용할 수 있습니다.&lt;/div&gt;
&lt;div&gt;Tohil의 발음은 취향에 따라 '토-힐(toe-heel)' 또는 '토-힐(toe-hill)'로 부를 수 있습니다.&lt;/div&gt;
&lt;div&gt;Tohil은 튜토리얼과 레퍼런스를 포함하여 계속해서 늘어나고 있는 문서들을 갖추고 있으며, &lt;a href=&quot;https://flightaware.github.io/tohil-docs/&quot;&gt;https://flightaware.github.io/tohil-docs/&lt;/a&gt; 에서 확인하실 수 있습니다.&lt;/div&gt;
&lt;pre id=&quot;code_1777345789734&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import tohil
&amp;gt;&amp;gt;&amp;gt; clock = 1616182348
&amp;gt;&amp;gt;&amp;gt; tohil.eval(f&quot;clock format {clock} -locale es -gmt 1&quot;, to=str)
'vie mar 19 19:32:28 GMT 2021'&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1777345801561&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; tohil.eval('set a [list a 1 b 2 c 3]')
'a 1 b 2 c 3'
&amp;gt;&amp;gt;&amp;gt; tohil.eval('return $a', to=list)
['a', '1', 'b', '2', 'c', '3']
&amp;gt;&amp;gt;&amp;gt; tohil.eval('return $a',to=dict)
{'a': '1', 'b': '2', 'c': '3'}

&amp;gt;&amp;gt;&amp;gt; a, b, c = tohil.eval(&quot;list 1 2 3&quot;, to=tuple)
&amp;gt;&amp;gt;&amp;gt; c
'3'&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1777345816883&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import tohil
&amp;gt;&amp;gt;&amp;gt; a = tohil.eval('list 1 [list 2 4 5] 3')
&amp;gt;&amp;gt;&amp;gt; print(a)
1 {2 4 5} 3

&amp;gt;&amp;gt;&amp;gt; import tohil
&amp;gt;&amp;gt;&amp;gt; tohil.eval('set a(99) goof')
'goof'
&amp;gt;&amp;gt;&amp;gt; tohil.eval('set a(5) foo')
'foo'
&amp;gt;&amp;gt;&amp;gt; tohil.getvar('a','99')
'goof'
&amp;gt;&amp;gt;&amp;gt; tohil.getvar(array='a',var='5')
'foo'
&amp;gt;&amp;gt;&amp;gt; tohil.getvar(array='a',var='16')


&amp;gt;&amp;gt;&amp;gt; tohil.eval('set a [list a 1 b 2 c 3]')
'a 1 b 2 c 3'
&amp;gt;&amp;gt;&amp;gt; tohil.subst(&quot;$a&quot;)
'a 1 b 2 c 3'
&amp;gt;&amp;gt;&amp;gt; tohil.eval('return $a')
'a 1 b 2 c 3'
&amp;gt;&amp;gt;&amp;gt; tohil.eval('return $a',to=list)
['a', '1', 'b', '2', 'c', '3']
&amp;gt;&amp;gt;&amp;gt; tohil.eval('return $a',to=dict)
{'a': '1', 'b': '2', 'c': '3'}

&amp;gt;&amp;gt;&amp;gt; tohil.eval(to=list,tcl_code=&quot;return [list 1 2 3 4]&quot;)
['1', '2', '3', '4']&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1777345861577&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require tohil

puts &quot;calling out to Python to add 5 + 5: [::tohil::eval &quot;5 + 5&quot;]&quot;

tohil::exec {
print('hello, world')
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bQKAky/dJMcaduZfLj/LSouSvL8tLdcGHQCRGNkDk/tohil-main.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tohil-main.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.33MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/722</guid>
      <comments>https://ihmin.tistory.com/722#entry722comment</comments>
      <pubDate>Tue, 28 Apr 2026 12:11:19 +0900</pubDate>
    </item>
    <item>
      <title>FastSignals</title>
      <link>https://ihmin.tistory.com/721</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://github.com/ispringtech/FastSignals&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/ispringtech/FastSignals&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Qt 스타일의 Signal 처리 라이브러리..&lt;/p&gt;
&lt;pre id=&quot;code_1770081088039&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;connect
emit
disconnect&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1770081131463&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Creates signal and connects 1 slot, calls 2 times, disconnects, calls again.
// Outputs:
//  13
//  17
#include &quot;libfastsignals/signal.h&quot;

using namespace fastsignals;

int main()
{
    signal&amp;lt;void(int)&amp;gt; valueChanged;
    connection conn;
    conn = valueChanged.connect([](int value) {
        cout &amp;lt;&amp;lt; value &amp;lt;&amp;lt; endl;
    });
    valueChanged(13);
    valueChanged(17);
    conn.disconnect();
    valueChanged(42);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/KLBnY/dJMcagK9IFE/mtZuKbAEdyY4Kjz8tWYci0/FastSignals-master.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;FastSignals-master.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.13MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>connect</category>
      <category>disconnect</category>
      <category>EMIT</category>
      <category>QT</category>
      <category>Signal</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/721</guid>
      <comments>https://ihmin.tistory.com/721#entry721comment</comments>
      <pubDate>Tue, 3 Feb 2026 10:13:30 +0900</pubDate>
    </item>
    <item>
      <title>LMDB를 이용한 Tree DB</title>
      <link>https://ihmin.tistory.com/719</link>
      <description>&lt;pre id=&quot;code_1767809067635&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;lmdb.h&amp;gt;

class TreeDB {
private:
	MDB_env *env = nullptr;
	MDB_dbi dbi;
	std::string dbPath;
	size_t currentMapSize;

	// DB 초기화 및 오픈 (공통 로직)
	void initDB(size_t newSize) {
		if (env) mdb_env_close(env); // 기존 환경 닫기

		mdb_env_create(&amp;amp;env);
		mdb_env_set_mapsize(env, newSize);
		// MDB_WRITEMAP: 쓰기 시 성능 향상 및 확장 시 유리
		int rc = mdb_env_open(env, dbPath.c_str(), MDB_NOSUBDIR, 0664);

		if (rc != 0) {
			throw std::runtime_error(&quot;DB Open Failed!&quot;);
		}

		MDB_txn *txn;
		mdb_txn_begin(env, NULL, 0, &amp;amp;txn);
		mdb_dbi_open(txn, NULL, 0, &amp;amp;dbi);
		mdb_txn_commit(txn);

		currentMapSize = newSize;
		std::cout &amp;lt;&amp;lt; &quot;[System] DB Capacity Updated: &quot; &amp;lt;&amp;lt; currentMapSize / 1024 / 1024 &amp;lt;&amp;lt; &quot;MB&quot; &amp;lt;&amp;lt; std::endl;
	}

public:
	TreeDB(const std::string&amp;amp; path, size_t initialSize = 1048576) : dbPath(path) { // 기본 1MB
		initDB(initialSize);
	}

	~TreeDB() {
		mdb_dbi_close(env, dbi);
		mdb_env_close(env);
	}

	// 용량 부족 시 자동 재시도 로직이 포함된 Insert
	// 노드 추가 (부모 경로 + 현재 이름)
	bool insertNode(const std::string&amp;amp; parentPath, const std::string&amp;amp; nodeName, const std::string&amp;amp; value) {
		std::string fullPath = parentPath.empty() ? nodeName : parentPath + &quot;/&quot; + nodeName;

		MDB_val key, data;
		key.mv_size = fullPath.size();
		key.mv_data = (void*)fullPath.c_str();
		data.mv_size = value.size();
		data.mv_data = (void*)value.c_str();

		while (true) {
			MDB_txn *txn;
			mdb_txn_begin(env, NULL, 0, &amp;amp;txn);

			int rc = mdb_put(txn, dbi, &amp;amp;key, &amp;amp;data, 0);

			if (rc == MDB_MAP_FULL) {
				// 용량이 꽉 찼을 경우 현재 트랜잭션 취소
				mdb_txn_abort(txn);

				// 용량을 2배로 키워서 DB 재오픈
				initDB(currentMapSize * 2);

				// 루프를 통해 다시 시도 (while true)
				continue; 
			} else if (rc != 0) {
				mdb_txn_abort(txn);
				return false;
			}

			mdb_txn_commit(txn);
			return true;
		}
	}

	// 바이너리 데이터 저장을 위한 오버로딩 또는 수정
	bool insertNode(const std::string&amp;amp; parentPath, const std::string&amp;amp; nodeName, const std::vector&amp;lt;uint8_t&amp;gt;&amp;amp; binaryData) {
		std::string fullPath = parentPath.empty() ? nodeName : parentPath + &quot;/&quot; + nodeName;

		MDB_val key, data;
		// 1. 키(경로) 설정
		key.mv_size = fullPath.size();
		key.mv_data = (void*)fullPath.c_str();

		// 2. 바이너리 데이터 설정
		data.mv_size = binaryData.size();
		data.mv_data = (void*)binaryData.data(); // 바이트 배열의 시작 주소

		while (true) {
			MDB_txn *txn;
			mdb_txn_begin(env, NULL, 0, &amp;amp;txn);

			int rc = mdb_put(txn, dbi, &amp;amp;key, &amp;amp;data, 0);

			if (rc == MDB_MAP_FULL) {
				mdb_txn_abort(txn);
				initDB(currentMapSize * 2);
				continue; 
			} else if (rc != 0) {
				mdb_txn_abort(txn);
				return false;
			}

			mdb_txn_commit(txn);
			return true;
		}
	}

	// 특정 노드 및 자식 노드 검색 
	void listChildren(const std::string&amp;amp; path) {
		MDB_txn *txn;
		MDB_cursor *cursor;
		mdb_txn_begin(env, NULL, MDB_RDONLY, &amp;amp;txn);
		mdb_cursor_open(txn, dbi, &amp;amp;cursor);

		MDB_val key, data;
		key.mv_size = path.size();
		key.mv_data = (void*)path.c_str();

		// 경로로 이동
		int rc = mdb_cursor_get(cursor, &amp;amp;key, &amp;amp;data, MDB_SET_RANGE);

		while (rc == 0) {
			std::string foundKey((char*)key.mv_data, key.mv_size);

			// 현재 경로로 시작하는 데이터만 출력 (자식들)
			if (foundKey.find(path) != 0) break;

			std::cout &amp;lt;&amp;lt; &quot;Path: &quot; &amp;lt;&amp;lt; foundKey &amp;lt;&amp;lt; &quot; | Value: &quot; &amp;lt;&amp;lt; (char*)data.mv_data &amp;lt;&amp;lt; std::endl;
			rc = mdb_cursor_get(cursor, &amp;amp;key, &amp;amp;data, MDB_NEXT);
		}

		mdb_cursor_close(cursor);
		mdb_txn_abort(txn);
	}

	// 특정 노드와 그 하위의 모든 자식 노드를 삭제하는 함수
	void deleteNodeRecursive(const std::string&amp;amp; path) {
		if (path.empty()) return;

		MDB_txn *txn;
		MDB_cursor *cursor;

		// 쓰기 트랜잭션 시작
		int rc = mdb_txn_begin(env, NULL, 0, &amp;amp;txn);
		if (rc != 0) return;

		rc = mdb_cursor_open(txn, dbi, &amp;amp;cursor);
		if (rc != 0) {
			mdb_txn_abort(txn);
			return;
		}

		MDB_val key, data;
		key.mv_size = path.size();
		key.mv_data = (void*)path.c_str();

		// 삭제를 시작할 위치(해당 경로)를 찾음
		rc = mdb_cursor_get(cursor, &amp;amp;key, &amp;amp;data, MDB_SET_RANGE);

		while (rc == 0) {
			std::string foundKey((char*)key.mv_data, key.mv_size);

			// 현재 찾은 키가 삭제하려는 path로 시작하는지 확인 (Prefix Check)
			// 예: path가 &quot;Users/Alice&quot;일 때 &quot;Users/Alice/ProjectA&quot;는 삭제 대상임
			if (foundKey.find(path) == 0) {
				// 해당 노드 삭제
				rc = mdb_cursor_del(cursor, 0);
				if (rc != 0) break;

				// 다음 노드로 이동 (삭제 후에는 현재 커서 위치가 다음 노드를 가리킴)
				rc = mdb_cursor_get(cursor, &amp;amp;key, &amp;amp;data, MDB_GET_CURRENT);
			} else {
				// 더 이상 해당 경로로 시작하는 키가 없으면 중단
				break;
			}
		}

		// 커서 닫기 및 트랜잭션 커밋 (실제 파일에 반영)
		mdb_cursor_close(cursor);
		mdb_txn_commit(txn);

		std::cout &amp;lt;&amp;lt; &quot;Successfully deleted path and its children: &quot; &amp;lt;&amp;lt; path &amp;lt;&amp;lt; std::endl;
	}

	// ASCII 문자열로 가져오기 (std::string 반환)
	std::string getNodeValueAscii(const std::string&amp;amp; fullPath) {
		MDB_txn *txn;
		// 읽기 전용 트랜잭션은 가볍고 빠릅니다.
		int rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &amp;amp;txn);
		if (rc != 0) return &quot;&quot;;

		MDB_val key, data;
		key.mv_size = fullPath.size();
		key.mv_data = (void*)fullPath.c_str();

		rc = mdb_get(txn, dbi, &amp;amp;key, &amp;amp;data);

		std::string result = &quot;&quot;;
		if (rc == 0) {
			// LMDB 내부 메모리 영역을 std::string으로 복사
			result.assign(reinterpret_cast&amp;lt;char*&amp;gt;(data.mv_data), data.mv_size);
		}

		mdb_txn_abort(txn); // 읽기 트랜잭션은 abort로 종료 (변경사항 없음)
		return result;
	}

	// Binary 데이터로 가져오기 (std::vector&amp;lt;uint8_t&amp;gt; 반환)
	std::vector&amp;lt;uint8_t&amp;gt; getNodeValueBinary(const std::string&amp;amp; fullPath) {
		MDB_txn *txn;
		int rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &amp;amp;txn);
		if (rc != 0) return {};

		MDB_val key, data;
		key.mv_size = fullPath.size();
		key.mv_data = (void*)fullPath.c_str();

		rc = mdb_get(txn, dbi, &amp;amp;key, &amp;amp;data);

		std::vector&amp;lt;uint8_t&amp;gt; result;
		if (rc == 0) {
			// 바이너리 데이터는 안전하게 vector로 복사하여 전달
			uint8_t* ptr = reinterpret_cast&amp;lt;uint8_t*&amp;gt;(data.mv_data);
			result.assign(ptr, ptr + data.mv_size);
		}

		mdb_txn_abort(txn);
		return result;
	}
};

int main() 
{
	TreeDB db(&quot;mytree.db&quot;);

	// 아스키 데이타 삽입
	db.insertNode(&quot;&quot;, &quot;Users&quot;, &quot;Root for users&quot;);
	db.insertNode(&quot;Users&quot;, &quot;Alice&quot;, &quot;Developer&quot;);
	db.insertNode(&quot;Users&quot;, &quot;Bob&quot;, &quot;Designer&quot;);
	db.insertNode(&quot;Users/Alice&quot;, &quot;ProjectA&quot;, &quot;Lead&quot;);

	// 바이너리 데이타 삽입
	std::vector&amp;lt;uint8_t&amp;gt; data;
	for(int i=0; i&amp;lt;10; i++) data.push_back(i);
	db.insertNode(&quot;Users/Alice&quot;, &quot;Data&quot;, data);

	// 트리 구조 출력
	std::cout &amp;lt;&amp;lt; &quot;--- Tree Structure under 'Users' ---&quot; &amp;lt;&amp;lt; std::endl;
	db.listChildren(&quot;Users&quot;);
	std::cout &amp;lt;&amp;lt; &quot;--- Tree Structure under 'Users/Alice' ---&quot; &amp;lt;&amp;lt; std::endl;
	db.listChildren(&quot;Users/Alice&quot;);

	// ASCII 데이터 읽기
	std::string value = db.getNodeValueAscii(&quot;Users/Bob&quot;);
	std::cout &amp;lt;&amp;lt; &quot;Value: &quot; &amp;lt;&amp;lt; value &amp;lt;&amp;lt; std::endl;

	// Binary 데이터 읽기
	std::vector&amp;lt;uint8_t&amp;gt; data2 = db.getNodeValueBinary(&quot;Users/Alice/Data&quot;);
	if (!data2.empty()) {
		for(int i=0; i&amp;lt;data2.size(); i++) {
			printf(&quot;0x%x &quot;, data2[i]);
		}
	}
	printf(&quot;\n&quot;);

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트..&lt;/p&gt;
&lt;pre id=&quot;code_1767809092987&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[MIN@DESKTOP-RSH0QT3 temp]$ g++ treedb.cpp  -llmdb

[MIN@DESKTOP-RSH0QT3 temp]$ ./a
[System] DB Capacity Updated: 1MB
--- Tree Structure under 'Users' ---
Path: Users | Value: Root for users
Path: Users/Alice | Value: Developer
Path: Users/Alice/Data | Value:
Path: Users/Alice/ProjectA | Value: Lead
Path: Users/Bob | Value: Designer
--- Tree Structure under 'Users/Alice' ---
Path: Users/Alice | Value: Developer
Path: Users/Alice/Data | Value:
Path: Users/Alice/ProjectA | Value: Lead
Value: Designer
0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9&lt;/code&gt;&lt;/pre&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>lmdb</category>
      <category>tree</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/719</guid>
      <comments>https://ihmin.tistory.com/719#entry719comment</comments>
      <pubDate>Thu, 8 Jan 2026 03:06:35 +0900</pubDate>
    </item>
    <item>
      <title>Prebuilt Tclkit</title>
      <link>https://ihmin.tistory.com/pages/Prebuilt-Tclkit</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;The&amp;nbsp;files&amp;nbsp;below&amp;nbsp;are&amp;nbsp;pre-built&amp;nbsp;Tclkit&amp;nbsp;binaries&amp;nbsp;for&amp;nbsp;various&amp;nbsp;Tcl/Tk&amp;nbsp;versions.&amp;nbsp;They&amp;nbsp;are&amp;nbsp;supported&amp;nbsp;only&amp;nbsp;on&amp;nbsp;64-bit&amp;nbsp;Windows.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.4&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/74BsG/dJMcaaRvB3s/mRB7HrX5z9Ki0Njw4wrxjK/tclkit-large-8.4.20-win-amd64.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclkit-large-8.4.20-win-amd64.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.93MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/dPzv7P/dJMcad1H1Vr/mhJfJDFK2FuwZU7Ds9Kh71/tclkit-small-8.4.20-win-amd64.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclkit-small-8.4.20-win-amd64.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.94MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.5&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bSiyne/dJMcachtTx8/jC9Zc7dyzQ0yk6mTSRslY0/tclkit-large-8.5.19-win-amd64.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclkit-large-8.5.19-win-amd64.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.63MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/VdcXQ/dJMcadUWA9s/2LEfxkh0oYX4AhLZkdaoD0/tclkit-small-8.5.19-win-amd64.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclkit-small-8.5.19-win-amd64.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.41MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8.6&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/NGgpq/dJMcahQDgC4/U4cZVpKiSSrZGGqm7CuWkk/tclkit-large-8.6.14-win-amd64.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclkit-large-8.6.14-win-amd64.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.96MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/lpcHN/dJMcahQDgC8/Ppkhrog7uB8kRD7Qasx1k0/tclkit-small-8.6.14-win-amd64.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclkit-small-8.6.14-win-amd64.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.82MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/FfbD5/dJMb99LOROt/D8rmhzTlWt1mxoFJxOkRQ1/tclkit-large-8.6.16-win-amd64.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclkit-large-8.6.16-win-amd64.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.97MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bAaS0E/dJMb99LOROv/87NS9hahXVow5SzBaikMA1/tclkit-small-8.6.16-win-amd64.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclkit-small-8.6.16-win-amd64.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.85MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/pages/Prebuilt-Tclkit</guid>
      <pubDate>Mon, 5 Jan 2026 23:10:40 +0900</pubDate>
    </item>
    <item>
      <title>Drawing clipping cap</title>
      <link>https://ihmin.tistory.com/717</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;OpenGL에서 솔리드 파트의 경우 Clipping 시에 cap을 씌우는 기능을 드디어 완료함..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 cap 씌우기전...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;527&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p4ORa/dJMcahXpTD3/QwJYs6Q7BYpPlXbvEiKbYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p4ORa/dJMcahXpTD3/QwJYs6Q7BYpPlXbvEiKbYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p4ORa/dJMcahXpTD3/QwJYs6Q7BYpPlXbvEiKbYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp4ORa%2FdJMcahXpTD3%2FQwJYs6Q7BYpPlXbvEiKbYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1059&quot; height=&quot;527&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;527&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 cap 씌운후...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nlU10/dJMcagqD0Eg/tzKsY11D0NM0ZhO6SKy880/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nlU10/dJMcagqD0Eg/tzKsY11D0NM0ZhO6SKy880/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nlU10/dJMcagqD0Eg/tzKsY11D0NM0ZhO6SKy880/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnlU10%2FdJMcagqD0Eg%2FtzKsY11D0NM0ZhO6SKy880%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1059&quot; height=&quot;540&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;plane도 그려봄..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coNKym/dJMcab3WIeC/TBDA7p1a8nzDQoxAAbMJ11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coNKym/dJMcab3WIeC/TBDA7p1a8nzDQoxAAbMJ11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coNKym/dJMcab3WIeC/TBDA7p1a8nzDQoxAAbMJ11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoNKym%2FdJMcab3WIeC%2FTBDA7p1a8nzDQoxAAbMJ11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1059&quot; height=&quot;528&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 방향으로 clipping..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;493&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbHtHM/dJMcaiWgPop/Ijbp1090dFdKkZInU37Ig1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbHtHM/dJMcaiWgPop/Ijbp1090dFdKkZInU37Ig1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbHtHM/dJMcaiWgPop/Ijbp1090dFdKkZInU37Ig1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbHtHM%2FdJMcaiWgPop%2FIjbp1090dFdKkZInU37Ig1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1059&quot; height=&quot;493&quot; data-origin-width=&quot;1059&quot; data-origin-height=&quot;493&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1058&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cr0PZV/dJMcaaYhqsb/Kn1a4xhvwOmESgAPzrHeL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cr0PZV/dJMcaaYhqsb/Kn1a4xhvwOmESgAPzrHeL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cr0PZV/dJMcaaYhqsb/Kn1a4xhvwOmESgAPzrHeL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcr0PZV%2FdJMcaaYhqsb%2FKn1a4xhvwOmESgAPzrHeL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1058&quot; height=&quot;530&quot; data-origin-width=&quot;1058&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>Clipping</category>
      <category>OpenGL</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/717</guid>
      <comments>https://ihmin.tistory.com/717#entry717comment</comments>
      <pubDate>Mon, 5 Jan 2026 23:04:09 +0900</pubDate>
    </item>
    <item>
      <title>Ray intersection with Embree 4</title>
      <link>https://ihmin.tistory.com/716</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Embree 4를 이용한.. Ray intersection..&lt;/p&gt;
&lt;pre id=&quot;code_1766752098867&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;embree4/rtcore.h&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;limits&amp;gt;

// 내부 에러 발생 시 호출
void errorHandler(void* userPtr, enum RTCError code, const char* str) {
    std::cerr &amp;lt;&amp;lt; &quot;Embree Error: &quot; &amp;lt;&amp;lt; str &amp;lt;&amp;lt; std::endl;
}

int main() {
    // 디바이스 및 장면(Scene) 초기화
    RTCDevice device = rtcNewDevice(nullptr);
    rtcSetDeviceErrorFunction(device, errorHandler, nullptr);
    RTCScene scene = rtcNewScene(device);

    // 삼각형 메시 지오메트리 생성
    RTCGeometry geom = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);

    // 정점 데이터 설정 (수백만 개 가능)
    float* vertices = (float*)rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, 3 * sizeof(float), 3);
    vertices[0] = 0.f; vertices[1] = 0.f; vertices[2] = 0.f; // v0
    vertices[3] = 1.f; vertices[4] = 0.f; vertices[5] = 0.f; // v1
    vertices[6] = 0.f; vertices[7] = 1.f; vertices[8] = 0.f; // v2

    // 인덱스 데이터 설정 (삼각형 연결 정보)
    unsigned* indices = (unsigned*)rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, 3 * sizeof(unsigned), 1);
    indices[0] = 0; indices[1] = 1; indices[2] = 2;

    // 지오메트리 확정 및 장면에 추가
    rtcCommitGeometry(geom);
    rtcAttachGeometry(scene, geom);
    rtcReleaseGeometry(geom); // 장면에 붙인 후 해제 가능 (참조 카운팅)

    // 장면 확정 (BVH 빌드 시작)
    rtcCommitScene(scene);

	// 레이 쿼리 정의
    RTCRayHit rayhit;
    rayhit.ray.org_x = 0.2f; rayhit.ray.org_y = 0.2f; rayhit.ray.org_z = -1.0f;
    rayhit.ray.dir_x = 0.0f; rayhit.ray.dir_y = 0.0f; rayhit.ray.dir_z = 1.0f;
    rayhit.ray.tnear = 0.0f;
    rayhit.ray.tfar = std::numeric_limits&amp;lt;float&amp;gt;::infinity();
    rayhit.ray.mask = -1;
    rayhit.ray.flags = 0;
    rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
    rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;

	// 쿼리
    RTCIntersectArguments args;
    rtcInitIntersectArguments(&amp;amp;args);
    args.feature_mask = RTC_FEATURE_FLAG_ALL; // 모든 기능 활성화 (성능에 따라 조절 가능)

    rtcIntersect1(scene, &amp;amp;rayhit, &amp;amp;args);

    // 결과 확인
    if (rayhit.hit.geomID != RTC_INVALID_GEOMETRY_ID) {
        std::cout &amp;lt;&amp;lt; &quot;충돌 발생! 거리: &quot; &amp;lt;&amp;lt; rayhit.ray.tfar &amp;lt;&amp;lt; std::endl;
        std::cout &amp;lt;&amp;lt; &quot;충돌한 면(Primitive) ID: &quot; &amp;lt;&amp;lt; rayhit.hit.primID &amp;lt;&amp;lt; std::endl;
    } else {
        std::cout &amp;lt;&amp;lt; &quot;충돌 없음&quot; &amp;lt;&amp;lt; std::endl;
    }

    // 정리
    rtcReleaseScene(scene);
    rtcReleaseDevice(device);

    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/716</guid>
      <comments>https://ihmin.tistory.com/716#entry716comment</comments>
      <pubDate>Fri, 26 Dec 2025 21:32:28 +0900</pubDate>
    </item>
    <item>
      <title>iconv 1.18</title>
      <link>https://ihmin.tistory.com/715</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;다른 dll 의존성 없게 static compile 해서 올려봄.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/blaew4/dJMcacalYc6/p1PzUyanXfL5JSQMLZdbmK/iconv_no_i18n.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;iconv_no_i18n.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.03MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>dll</category>
      <category>iconv</category>
      <category>Static</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/715</guid>
      <comments>https://ihmin.tistory.com/715#entry715comment</comments>
      <pubDate>Fri, 7 Nov 2025 15:48:48 +0900</pubDate>
    </item>
    <item>
      <title>cuda_voxelizer</title>
      <link>https://ihmin.tistory.com/714</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Forceflow/cuda_voxelizer&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Forceflow/cuda_voxelizer&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CUDA를 이용해서 빠른 시간안에 복셀화를 시켜주는 프로그램.. 물론 CPU도 지원..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kMRdU/dJMcac9f31q/kaq3KrAPaYOKEoPOJBFNlk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kMRdU/dJMcac9f31q/kaq3KrAPaYOKEoPOJBFNlk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kMRdU/dJMcac9f31q/kaq3KrAPaYOKEoPOJBFNlk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkMRdU%2FdJMcac9f31q%2Fkaq3KrAPaYOKEoPOJBFNlk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;292&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;background-color: #ffffff; color: #1f2328; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;Grid size&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;GPU (GTX 1050 TI)&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;CPU (Intel i7 8750H, 12 threads)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;64&amp;sup3;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;0.2 ms&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;39.8 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;128&amp;sup3;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;0.3 ms&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;63.6 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;256&amp;sup3;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;0.6 ms&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;118.2 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;512&amp;sup3;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;1.8 ms&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;308.8 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffffff;&quot;&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;1024&amp;sup3;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;8.6 ms&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;1047.5 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #f6f8fa;&quot;&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;2048&amp;sup3;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;44.6 ms&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;4147.4 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1762417061635&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# generates a 256 x 256 x 256 vox-based voxel model which will be stored in bunny_256.vox.
$ cuda_voxelizer -f bunny.ply -s 256 

# generates a solid (filled) 64 x 64 x 64 .obj voxel model which will be stored in torus_64.obj.
$ cuda_voxelizer -f torus.ply -s 64 -o obj -solid&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/cTXsC6/dJMcadmNcmK/cshRJNM2O5sU7MT8mPEJ6K/cuda_voxelizer_v0.6.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;cuda_voxelizer_v0.6.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.64MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트해보니.. 잘됨.&lt;/p&gt;
&lt;pre id=&quot;code_1762417771292&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cuda_voxelizer.exe -f bunny.obj -s 100 -o obj
## CUDA VOXELIZER
CUDA Voxelizer v0.6 by Jeroen Baert
https://github.com/Forceflow/cuda_voxelizer - mail (at) jeroen-baert (dot) be

## PROGRAM PARAMETERS
[Info] Filename: bunny.obj
[Info] Grid size: 100
[Info] Output format: obj file (cubes)
[Info] Using CPU-based voxelization: No (default: No)
[Info] Using Solid Voxelization: No (default: No)

## READ MESH
[I/O] Reading mesh from bunny.obj
[Mesh] Number of triangles: 22236
[Mesh] Number of vertices: 11120
[Mesh] Computing bbox

## VOXELISATION SETUP
[Voxelization] Bounding Box: (0.000288,-0.073080,-0.008127)-(0.627064,0.553695,0.618648)
[Voxelization] Grid size: 100 100 100
[Voxelization] Triangles: 22236
[Voxelization] Unit length: x: 0.006268 y: 0.006268 z: 0.006268

## CUDA INIT
[CUDA] CUDA device(s) found, picking best one
[CUDA] GPU Device 0: &quot;Pascal&quot; with compute capability 6.1
[CUDA] Best device: Quadro P1000
[CUDA] Available device memory: 3363 of 4095 MB

## TRIANGLES TO GPU TRANSFER
[Mesh] Allocating 781 KB of CUDA-managed UNIFIED memory for triangle data
[Mesh] Copy 22236 triangles to CUDA-managed UNIFIED memory
[Perf] Mesh transfer time to GPU: 164.6 ms
[Voxel Grid] Allocating 122 KB of CUDA-managed UNIFIED memory for Voxel Grid

## GPU VOXELISATION
[Perf] Voxelization GPU time: 0.1 ms

## FILE OUTPUT
[I/O] Writing data in obj voxels format to file bunny.obj_100_voxels.obj
[I/O] Writing to file: 0%...25%...50%...75%...100%
[I/O] Reordering / Optimizing mesh with Trimesh2
[I/O] Writing final mesh to file bunny.obj_100_voxels.obj

## STATS
[Perf] Total runtime: 4198.3 ms&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1061&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0sv6b/dJMcad1oL21/m124RCR6rFJjmIaZyvbStk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0sv6b/dJMcad1oL21/m124RCR6rFJjmIaZyvbStk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0sv6b/dJMcad1oL21/m124RCR6rFJjmIaZyvbStk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0sv6b%2FdJMcad1oL21%2Fm124RCR6rFJjmIaZyvbStk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1061&quot; height=&quot;560&quot; data-origin-width=&quot;1061&quot; data-origin-height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1069&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AaF8j/dJMcahJuQvc/y9fs9fMt1yJTkzxIqrNp9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AaF8j/dJMcahJuQvc/y9fs9fMt1yJTkzxIqrNp9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AaF8j/dJMcahJuQvc/y9fs9fMt1yJTkzxIqrNp9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAaF8j%2FdJMcahJuQvc%2Fy9fs9fMt1yJTkzxIqrNp9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1069&quot; height=&quot;564&quot; data-origin-width=&quot;1069&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자 커피 사줘야겠네..&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends2&quot; data-emoticon-name=&quot;041&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends2/large/041.png&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends2/large/041.png&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>CPU</category>
      <category>GPU</category>
      <category>obj</category>
      <category>PLY</category>
      <category>trimesh2</category>
      <category>voxelizer</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/714</guid>
      <comments>https://ihmin.tistory.com/714#entry714comment</comments>
      <pubDate>Thu, 6 Nov 2025 17:17:53 +0900</pubDate>
    </item>
    <item>
      <title>win-iconv</title>
      <link>https://ihmin.tistory.com/713</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/win-iconv/win-iconv&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/win-iconv/win-iconv&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;windows api로만 이루어진 iconv 대용 프로그램.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딸랑 실행파일 하나면 있으면 되니 편함..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일해서 올려봄..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/v1Gh4/dJMcaiuRVV0/H8tDuObQdcrKpuZmVO6YZK/win_iconv_exe.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;win_iconv_exe.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.07MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통의 경우 파일 내부의 dll은 필요없으나.. 아래의 경우 환경변수로 사용할수 있음.&lt;/p&gt;
&lt;pre id=&quot;code_1762408268671&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENVIRONMENT VARIABLE:
    WINICONV_LIBICONV_DLL
        If $WINICONV_LIBICONV_DLL is set, win_iconv uses the DLL.  If
        loading the DLL or iconv_open() failed, falls back to internal
        conversion.  If a few DLL are specified as comma separated list,
        the first loadable DLL is used.  The DLL should have
        iconv_open(), iconv_close() and iconv().  Or libiconv_open(),
        libiconv_close() and libiconv().
        (only available when USE_LIBICONV_DLL is defined at compile time)

Win32 API does not support strict encoding conversion for some codepage.
And MLang function drops or replaces invalid bytes and does not return
useful error status as iconv does.  This implementation cannot be used for
encoding validation purpose.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트..&lt;/p&gt;
&lt;pre id=&quot;code_1762408129535&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;C:\&amp;gt; win_iconv.exe -f utf-8 -t cp949 test.txt &amp;gt; test.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>API</category>
      <category>iconv</category>
      <category>winiconv</category>
      <category>win_iconv</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/713</guid>
      <comments>https://ihmin.tistory.com/713#entry713comment</comments>
      <pubDate>Thu, 6 Nov 2025 14:52:32 +0900</pubDate>
    </item>
    <item>
      <title>.ui 파일을 동적으로 탑재하기</title>
      <link>https://ihmin.tistory.com/712</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://ds31x.tistory.com/250&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ds31x.tistory.com/250&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 Qt Designer로 생성한 ui 파일을 Qt 위젯으로 동적 탑재하는 방법.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpne89/dJMcaeeVqK4/iGjYmKYnaFz9iHlZv7d1UK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpne89/dJMcaeeVqK4/iGjYmKYnaFz9iHlZv7d1UK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpne89/dJMcaeeVqK4/iGjYmKYnaFz9iHlZv7d1UK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpne89%2FdJMcaeeVqK4%2FiGjYmKYnaFz9iHlZv7d1UK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1130&quot; height=&quot;644&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/OutZc/dJMcacak97c/0y3kvuWu9F4QJMUElDtwN1/Ex1_QtDesigner.ui?attach=1&amp;amp;knm=tfile.ui&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;Ex1_QtDesigner.ui&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1762260969571&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os
import sys

# PySide6에서 필요한 클래스들 import
from PySide6.QtWidgets import (
    QApplication,      # 어플리케이션 객체
    QMainWindow,       # 메인 윈도우 프레임
    QLineEdit,         # 한 줄 텍스트 입력 위젯
    QLabel             # 텍스트 표시 위젯
)
from PySide6.QtUiTools import QUiLoader     # .ui 파일을 런타임에 로드하는 도구
from PySide6.QtCore import QFile            # Qt 파일 입출력을 위한 클래스


# 메인 윈도우 클래스 정의
class MainWindow(QMainWindow):
    def __init__(self, ui_fstr):
        super().__init__()

        # UI 파일(.ui)로부터 위젯 트리를 생성하여 중앙 위젯으로 설정
        self.wnd = self.ds_get_wnd_from_ui(ui_fstr)

        # 위젯 참조를 찾아서 시그널-슬롯 연결
        self.ds_setup()

        # 생성된 위젯을 QMainWindow의 중앙에 배치
        self.setCentralWidget(self.wnd)
        self.show()

    # UI 내부 위젯에 접근하고 이벤트를 연결하는 함수
    def ds_setup(self):
        # objectName으로 QLineEdit와 QLabel 찾기
        self.lineEdit = self.wnd.findChild(QLineEdit, &quot;lineEdit&quot;)
        self.label = self.wnd.findChild(QLabel, &quot;label&quot;)

        # UI에 필수 위젯이 없다면 오류 발생
        # 누락된 위젯들 확인
        missing_widgets = []
        if not self.lineEdit:
            missing_widgets.append(&quot;lineEdit&quot;)
        if not self.label:
            missing_widgets.append(&quot;label&quot;)
        
        if missing_widgets:
            raise AttributeError(f&quot;UI에 다음 위젯들이 없습니다: {', '.join(missing_widgets)}&quot;)
        

        # returnPressed 시 라벨 업데이트
        self.lineEdit.returnPressed.connect(self.ds_update_label)

    # 입력된 텍스트를 라벨에 표시하는 슬롯
    def ds_update_label(self):
        self.label.setText(f'Hello, {self.lineEdit.text()}')

    # .ui 파일을 열어서 QWidget으로 로딩하는 함수
    def ds_get_wnd_from_ui(self, ui_fstr):
        ui_loader = QUiLoader()

        # 현재 파일의 디렉토리 기준으로 .ui 파일 경로 구성
        root_dir = os.path.dirname(os.path.abspath(__file__))
        ui_path = os.path.join(root_dir, ui_fstr)

        # QFile 객체로 .ui 파일 준비
        ui_file = QFile(ui_path)
        if not ui_file.exists():
            raise FileNotFoundError(f&quot;UI 파일이 존재하지 않습니다: {ui_path}&quot;)

        # 파일 열고 로드
        if not ui_file.open(QFile.ReadOnly):
            raise IOError(f&quot;UI 파일을 열 수 없습니다: {ui_path}&quot;)

        try:
            wnd = ui_loader.load(ui_file, self)  # parent를 self로 설정
            if wnd is None:
                raise RuntimeError(f&quot;UI 파일 로딩 실패: {ui_path}&quot;)
            return wnd
        finally:
            ui_file.close()  # 예외 발생해도 반드시 닫힘


# 애플리케이션 진입점
if __name__ == '__main__':
    app = QApplication(sys.argv)                 # Qt 애플리케이션 생성
    window = MainWindow('Ex1_QtDesigner.ui')     # 메인 윈도우 클래스 인스턴스 생성
    sys.exit(app.exec())                         # 이벤트 루프 실행&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 결과.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;202&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rwxBg/dJMcacVIi2i/T7VwkwqehlnyLiOkEtJDpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rwxBg/dJMcacVIi2i/T7VwkwqehlnyLiOkEtJDpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rwxBg/dJMcacVIi2i/T7VwkwqehlnyLiOkEtJDpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrwxBg%2FdJMcacVIi2i%2FT7VwkwqehlnyLiOkEtJDpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;202&quot; height=&quot;132&quot; data-origin-width=&quot;202&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>designer</category>
      <category>QT</category>
      <category>UI</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/712</guid>
      <comments>https://ihmin.tistory.com/712#entry712comment</comments>
      <pubDate>Tue, 4 Nov 2025 21:57:48 +0900</pubDate>
    </item>
    <item>
      <title>메인 스크립트인지 판단하기</title>
      <link>https://ihmin.tistory.com/711</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;간혹 스크립틀 작성 후 테스트 코드를 작성할 때 메인 스크립트인지 아닌지를 판단해야 할 필요가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 판단은 아래와 같이 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1761612402175&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# a.tcl

if {[info exists argv0] &amp;amp;&amp;amp; ([file tail [info script]] eq [file tail $argv0])} {
	puts &quot;this is main script&quot;
} else {
	puts &quot;this is sub script&quot;
}

source b.tcl&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1761612649391&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# b.tcl

if {[info exists argv0] &amp;amp;&amp;amp; ([file tail [info script]] eq [file tail $argv0])} {
	puts &quot;this is main script&quot;
} else {
	puts &quot;this is sub script&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행을 해보면 a.tcl은 메인 스크립트로, b.tcl은 서브 스크립트로 판단이 잘 됨을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1761612690695&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tclsh85 a.tcl
this is main script
this is sub script&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Tcl &amp;amp; Tk/팁 (Tip)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/711</guid>
      <comments>https://ihmin.tistory.com/711#entry711comment</comments>
      <pubDate>Tue, 28 Oct 2025 09:52:17 +0900</pubDate>
    </item>
    <item>
      <title>libcpr</title>
      <link>https://ihmin.tistory.com/710</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/libcpr/cpr&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/libcpr/cpr&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cpr (C++ Requests)은 libcurl을 간단히 감싼 래퍼로 아래와 같이 파일 다운로드도 간단히 할 수 있음.&lt;/p&gt;
&lt;pre id=&quot;code_1761206132173&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# g++ test.cpp -lcpr

#include &amp;lt;fstream&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cpr/cpr.h&amp;gt;

int main() {    
    const std::string url = &quot;https://github.com/libcpr/cpr/archive/refs/tags/1.12.0.zip&quot;;
    const std::string output_filename = &quot;download.zip&quot;;
    
    std::ofstream output_file(output_filename, std::ios::binary);

    if (!output_file.is_open()) {
        std::cerr &amp;lt;&amp;lt; &quot;파일을 열 수 없습니다: &quot; &amp;lt;&amp;lt; output_filename &amp;lt;&amp;lt; std::endl;
        return 1;
    }

    // CPR 세션 생성
    cpr::Session session;
    session.SetUrl(cpr::Url{url});
    
    // 다운로드 요청 실행
    // cpr::Download를 사용하여 응답 본문을 파일 스트림에 직접 기록
    cpr::Response r = session.Download(output_file);

    // 다운로드 완료 후 파일 스트림 닫기
    output_file.close();

    // 응답 상태 확인
    if (r.status_code == 200) {
        std::cout &amp;lt;&amp;lt; &quot;파일 다운로드 성공: &quot; &amp;lt;&amp;lt; output_filename &amp;lt;&amp;lt; std::endl;
    } else {
        std::cerr &amp;lt;&amp;lt; &quot;파일 다운로드 실패. HTTP 상태 코드: &quot; &amp;lt;&amp;lt; r.status_code &amp;lt;&amp;lt; std::endl;
        std::cerr &amp;lt;&amp;lt; &quot;오류 메시지: &quot; &amp;lt;&amp;lt; r.error.message &amp;lt;&amp;lt; std::endl;
        // 다운로드 실패 시 생성된 불완전한 파일 삭제 (선택 사항)
        remove(output_filename.c_str());
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/710</guid>
      <comments>https://ihmin.tistory.com/710#entry710comment</comments>
      <pubDate>Thu, 23 Oct 2025 16:57:21 +0900</pubDate>
    </item>
    <item>
      <title>절대 패스 &amp;lt;-&amp;gt; 상대 패스 상호 변환</title>
      <link>https://ihmin.tistory.com/709</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://likle.github.io/cwalk/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://likle.github.io/cwalk/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/likle/cwalk&quot;&gt;https://github.com/likle/cwalk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhDQF/dJMb9aX0D1N/Ta2JSDbvd9tyJkfGP0kJW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhDQF/dJMb9aX0D1N/Ta2JSDbvd9tyJkfGP0kJW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhDQF/dJMb9aX0D1N/Ta2JSDbvd9tyJkfGP0kJW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhDQF%2FdJMb9aX0D1N%2FTa2JSDbvd9tyJkfGP0kJW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;250&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C/C++용으로 아주 괜찮은 절대 패스 &amp;lt;-&amp;gt; 상대 패스 상호 변환 라이브러리.. cwalk..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우즈/리눅스 스타일도 지원..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 간단한 래퍼 함수를 만들어봄..&lt;/p&gt;
&lt;pre id=&quot;code_1761200105918&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;limits.h&amp;gt; // FILENAME_MAX 
#include &amp;lt;cwalk.h&amp;gt;

std::string Rel2AbsPath(const std::string&amp;amp; base, const std::string&amp;amp; relative, bool unix_style) 
{
	if(unix_style)
		cwk_path_set_style(CWK_STYLE_UNIX);
	else
		cwk_path_set_style(CWK_STYLE_WINDOWS);

	char buffer[FILENAME_MAX];
	cwk_path_get_absolute(base.c_str(), relative.c_str(), buffer, sizeof(buffer));
	return std::string(buffer);
}

std::string Abs2RelPath(const std::string&amp;amp; base, const std::string&amp;amp; absolute, bool unix_style) 
{
	if(unix_style)
		cwk_path_set_style(CWK_STYLE_UNIX);
	else
		cwk_path_set_style(CWK_STYLE_WINDOWS);

	char buffer[FILENAME_MAX];
	cwk_path_get_relative(base.c_str(), absolute.c_str(), buffer, sizeof(buffer));
	return std::string(buffer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/UZhtl/dJMb9NohkGK/jkfhY4UpvGnhCDL4u6kjtK/cwalk-master.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;cwalk-master.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.11MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>abs2rel</category>
      <category>cwalk</category>
      <category>rel2abs</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/709</guid>
      <comments>https://ihmin.tistory.com/709#entry709comment</comments>
      <pubDate>Thu, 23 Oct 2025 15:16:30 +0900</pubDate>
    </item>
    <item>
      <title>msgpack</title>
      <link>https://ihmin.tistory.com/708</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://github.com/jdc8/msgpack&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/jdc8/msgpack&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순수 Tcl로 구현된 오브젝트 직렬화 패키지입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1760367174637&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예제1
package require msgpack

set p [msgpack::packer new]

$p pack int 123456789
$p pack str &quot;A MessagePack example&quot;
$p pack dict int str {1 one 2 two}
set packed_data [$p data]

set u [msgpack::unpacker new]
$u unpack_string $packed_data
# {{integer 123456789} {str {A MessagePack example}} {map {{integer 1} {str one} {integer 2} {str two}}}}
$u destroy&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1760367296164&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예제2
set packed_data &quot;&quot;
append packed_data [msgpack pack int 0xFFFFFFFF]
append packed_data [msgpack pack bin &quot;A Utility example&quot;]
append packed_data [msgpack pack dict int str {3 three 4 four}]}

puts [msgpack unpack $packed_data]
# {{integer 4294967295} {bin {A Utility example}} {map {{integer 3} {str three} {integer 4} {str four}}}}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1760367316476&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예제3
set up [msgpack::unpacker new]

proc xor {n type data} {
    set res {}
    foreach b [split $data {}] {
        set code [scan $b %c]
        append res [format %c [expr { $code ^ $n }]]
    }

    return [list encrypted $res]
}

$up set_ext_unpacker 100 {xor 5}
# Prints &quot;{encrypted Hello!}&quot;.
puts [$up unpack_string [msgpack pack ext 100 M`iij$]]
$up destroy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bQhfOt/dJMb9MW90t9/DY4gxxQVHHWE99utXT2An1/msgpack-master.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;msgpack-master.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.03MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/708</guid>
      <comments>https://ihmin.tistory.com/708#entry708comment</comments>
      <pubDate>Mon, 13 Oct 2025 23:49:59 +0900</pubDate>
    </item>
    <item>
      <title>Ttk file selection dialog</title>
      <link>https://ihmin.tistory.com/707</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://chiselapp.com/user/schelte/repository/fsdialog/home&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://chiselapp.com/user/schelte/repository/fsdialog/home&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tk의 파일 선택 커맨드는 윈도우와 맥에서는 O/S 네이티브 대화상자를 사용하고 유닉스 계열 플랫폼에서는 매우 단순한 대화상자가 사용됩니다. 이 프로젝트는 이런 플랫폼에서 공통으로 사용하고 더 보기 좋은 대화상자를 제공하기 위해 시작되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 1.0 버전은 리눅스 버전의 Tk 코어에 포함될 가능성을 염두에 두고 설계되었습니다. 하지만 이에 대한 저항이 너무 커서, 2.0 버전에서는 이러한 전략이 폐기되었습니다. 이제 이 패키지는 auto_path 아래의 디렉토리에 위치하도록 되어 있습니다. 그런 다음 `[package require fsdialog]` 명령으로 패키지를 불러올 수 있습니다. 이렇게 하면 기본적으로 내장된 tk_getOpenFile, tk_getSaveFile, tk_chooseDirectory 함수들이 이 패키지의 버전으로 대체됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmIZi1/btsQ6LxdKdL/WcSaRNozSQ65XKuvot7dok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmIZi1/btsQ6LxdKdL/WcSaRNozSQ65XKuvot7dok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmIZi1/btsQ6LxdKdL/WcSaRNozSQ65XKuvot7dok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmIZi1%2FbtsQ6LxdKdL%2FWcSaRNozSQ65XKuvot7dok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;702&quot; height=&quot;512&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/b619Ft/dJMb8V0O8DD/HKS4qQr0cqA5sUB7gMRfI1/fsdialog.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;fsdialog.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.16MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/707</guid>
      <comments>https://ihmin.tistory.com/707#entry707comment</comments>
      <pubDate>Mon, 13 Oct 2025 11:09:08 +0900</pubDate>
    </item>
    <item>
      <title>ticklEcharts 3.2.8</title>
      <link>https://ihmin.tistory.com/706</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://github.com/nico-robert/ticklecharts&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/nico-robert/ticklecharts&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apache ECharts 를 Tcl로 바인딩한 패키지 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;5002&quot; data-origin-height=&quot;2902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqUN0C/btsQ76AwhJk/GNAVksSzkTDiZH1Gm81I41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqUN0C/btsQ76AwhJk/GNAVksSzkTDiZH1Gm81I41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqUN0C/btsQ76AwhJk/GNAVksSzkTDiZH1Gm81I41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqUN0C%2FbtsQ76AwhJk%2FGNAVksSzkTDiZH1Gm81I41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;5002&quot; height=&quot;2902&quot; data-origin-width=&quot;5002&quot; data-origin-height=&quot;2902&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1760276075286&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# line + bar on same canvas.
package require ticklecharts

# Initializes a new 2D Chart Class.
set chart [ticklecharts::chart new]

# Set options
$chart SetOptions -tooltip {show True trigger &quot;axis&quot; axisPointer {type &quot;cross&quot; crossStyle {color &quot;#999&quot;}}} \
                  -grid {left &quot;3%&quot; right &quot;4%&quot; bottom &quot;3%&quot; containLabel &quot;True&quot;} \
                  -legend {}
               
$chart Xaxis -data [list {&quot;Mon&quot; &quot;Tue&quot; &quot;Wed&quot; &quot;Thu&quot; &quot;Fri&quot; &quot;Sat&quot; &quot;Sun&quot;}] \
             -axisPointer {type &quot;shadow&quot;}

# Encapsulates the string with braces + quotes or use 'ticklecharts::eString'
# class for 'formatter' property (See '# string template' section).
$chart Yaxis -name &quot;Precipitation&quot; -position &quot;left&quot; -min 0 -max 250 -interval 50 \
                                   -axisLabel {formatter {&quot;{value} ml&quot;}}
$chart Yaxis -name &quot;Temperature&quot;   -position &quot;right&quot; -min 0 -max 25  -interval 5 \
                                   -axisLabel [list formatter [new estr &quot;{value} &amp;deg;C&quot;]]

# Add bars series.
$chart Add &quot;barSeries&quot; -name &quot;Evaporation&quot; \
                       -data [list {2.0 4.9 7.0 23.2 25.6 76.7 135.6 162.2 32.6 20.0 6.4 3.3}]
                    
$chart Add &quot;barSeries&quot; -name &quot;Precipitation&quot; \
                       -data [list {2.6 5.9 9.0 26.4 28.7 70.7 175.6 182.2 48.7 18.8 6.0 2.3}]                    

# Add line series.                  
$chart Add &quot;lineSeries&quot; -name &quot;Temperature&quot; \
                        -yAxisIndex 1 \
                        -data [list {2.0 2.2 3.3 4.5 6.3 10.2 20.3 23.4 23.0 16.5 12.0 6.2}]

# Output
$chart Render&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/baSPOL/dJMb8XYDRCu/hgoKmkQycwDfwdWie9XKc0/ticklecharts-3.2.8.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;ticklecharts-3.2.8.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;18.02MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/706</guid>
      <comments>https://ihmin.tistory.com/706#entry706comment</comments>
      <pubDate>Sun, 12 Oct 2025 22:35:00 +0900</pubDate>
    </item>
    <item>
      <title>toplevel의 타이틀바를 감추고 아웃라인 그리기</title>
      <link>https://ihmin.tistory.com/705</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 코드는 toplevel의 타이틀바를 감추고 아웃라인을 그리는 코드입니다. 프로그램 초기 구동 시 스플래쉬 윈도우를 그리는 데 사용하면 좋을 듯하네요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;230&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLiupX/btsQ7sp6SGb/DhzHsf6TTOFaJOulRMKIp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLiupX/btsQ7sp6SGb/DhzHsf6TTOFaJOulRMKIp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLiupX/btsQ7sp6SGb/DhzHsf6TTOFaJOulRMKIp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLiupX%2FbtsQ7sp6SGb%2FDhzHsf6TTOFaJOulRMKIp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;230&quot; height=&quot;219&quot; data-origin-width=&quot;230&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1760112251084&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set win [toplevel .option -relief solid \
			-class Toplevel -borderwidth 0 -highlightthickness 1 \
			-highlightbackground [::tk::Darken &quot;#30404A&quot; 85] \
			-highlightcolor [::tk::Darken &quot;#30404A&quot; 85]]
wm overrideredirect $win 1; # hide title bar&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/팁 (Tip)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/705</guid>
      <comments>https://ihmin.tistory.com/705#entry705comment</comments>
      <pubDate>Sat, 11 Oct 2025 01:06:36 +0900</pubDate>
    </item>
    <item>
      <title>TCLFPDF 1.7.2</title>
      <link>https://ihmin.tistory.com/704</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://github.com/lamuzzachiodi/tclfpdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/lamuzzachiodi/tclfpdf&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 확장 패키지는 PHP용 tFPDF(1.33)를 TCL로 포팅하는 것을 목표로 합니다. tFPDF는 FPDF(1.85)를 수정하여 UTF-8 지원을 추가한 클래스입니다. 따라서 이전 2014년 버전의 완전한 업데이트이며, 이전 버전과의 호환성을 유지하면서도 UTF-8을 완벽하게 지원합니다. 예제나 애드온을 최소한의 노력으로 포팅할 수 있게끔 tFPDF 프로그램의 이름과 구조를 최대한 원본에 가깝게 유지하려고 노력했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1760021662534&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require tclfpdf
namespace import  ::tclfpdf::*

AddPage;
# Add a Unicode font (uses UTF-8)
AddFont &quot;DejaVu&quot; &quot;&quot; &quot;DejaVuSansCondensed.ttf&quot; 1;
SetFont &quot;DejaVu&quot; &quot;&quot; 14;
Write 8 &quot;		-----
English: Hello World
Greek: &amp;Gamma;&amp;epsilon;&amp;iota;ά &amp;sigma;&amp;omicron;&amp;upsilon; &amp;kappa;ό&amp;sigma;&amp;mu;&amp;omicron;&amp;sigmaf;
Polish: Witaj świecie
Portuguese: Ol&amp;aacute; mundo
Spanish: Hola mundo
Russian: Здравствулте мир
Vietnamese: Xin ch&amp;agrave;o thế giới
		------&quot;;
Ln 10;		
AddFont &quot;simhei&quot; &quot;&quot; &quot;simhei.ttf&quot; 1;
SetFont &quot;simhei&quot; &quot;&quot; 20;		
Write 10 &quot;Chinese: 你好世界&quot;;
#Select a standard font (uses windows-1252)
SetFont  &quot;Arial&quot; &quot;&quot; 14;
Ln 10;
Write 5 &quot;The file size of this PDF is only 16 KB.&quot;;
Output &quot;utf8.pdf&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/byML77/dJMb9Xde5q7/LA0I8MsfKkdxklgC2lN6u0/tclfpdf-1.7.2.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclfpdf-1.7.2.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.29MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/704</guid>
      <comments>https://ihmin.tistory.com/704#entry704comment</comments>
      <pubDate>Thu, 9 Oct 2025 23:54:50 +0900</pubDate>
    </item>
    <item>
      <title>Drag &amp;amp; Drop 패키지 tkDND</title>
      <link>https://ihmin.tistory.com/pages/Drag-Drop-%ED%8C%A8%ED%82%A4%EC%A7%80-tkDND</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;tkDND&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tkDND(Tk Drag &amp;amp; Drop)는 Tk 위젯에서 드래그 앤 드롭을&amp;nbsp; 가능하게 해주는 확장 라이브러리입니다. 원래 드래그 앤 드롭 기능은 플랫폼 의존성이 매우 강한 처리로, Windows와 X 윈도우 시스템에서는 겉보기에는 비슷하게 동작하더라도 프로그래밍 방식이나 사용하는 API가 완전히 다르기 때문에 네이티브 API로 직접 구현하려면 꽤 힘든 작업입니다. 하지만 tkDND는 이러한 차이를 잘 흡수하여, 동일한 Tcl 코드로 Windows에서도 X 윈도우 시스템에서도 드래그 앤 드롭을 간단하게 구현할 수 있습니다. 게다가 단순히 Tk 위젯 간만이 아니라, Tk 위젯과 다른 애플리케이션의 아이콘 등과도 드래그 앤 드롭 동작을 할 수 있습니다. 이로써 편리한 데스크탑 도구를 누구나 손쉽게 만들 수 있게 되었습니다.&lt;br /&gt;&lt;br /&gt;tkDND는 George Petasis 씨에 의해 개발된 패키지로, 이 &lt;a href=&quot;http://www.iit.demokritos.gr/~petasis/Tcl/tkDND/tkDND.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;페이지&lt;/a&gt;에서 다운로드할 수 있습니다. 또한 &lt;a href=&quot;https://sourceforge.net/projects/tkdnd/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SourceForge&lt;/a&gt;나 &lt;a href=&quot;https://github.com/petasis/tkdnd&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github&lt;/a&gt;에도 오픈소스 프로젝트 페이지가 있으며, 이곳에서도 구할 수 있습니다. 최신 버전은 2.8입니다. Windows용 바이너리 DLL도 배포되고 있으며, 2015년 2월 28일 현재 32비트 버전은 2.8, 64비트 버전은 2.7이 배포되고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;tkDND의 드래그 &amp;amp; 드롭&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;위젯 간 드래그 &amp;amp; 드롭&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터, 여러분이 궁금해하실 드래그 &amp;amp; 드롭의 실제 코딩 방법을 소개하겠습니다. 먼저&amp;nbsp;간단한&amp;nbsp;샘플부터&amp;nbsp;시작하죠.&amp;nbsp;tkDND를&amp;nbsp;사용하면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Tk 위젯끼리&lt;/li&gt;
&lt;li&gt;다른 애플리케이션(예: 탐색기)에서 Tk 위젯으로&lt;/li&gt;
&lt;li&gt;Tk&amp;nbsp;위젯에서&amp;nbsp;다른&amp;nbsp;애플리케이션(압축&amp;nbsp;툴&amp;nbsp;등)으로&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드래그 &amp;amp; 드롭을 구현할 수 있지만, 기본은 가장 위의 &quot;Tk 위젯끼리&quot; 입니다.&amp;nbsp; 그럼,&amp;nbsp;그&amp;nbsp;간단한&amp;nbsp;샘플&amp;nbsp;코드는&amp;nbsp;다음과&amp;nbsp;같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759289322844&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require tkdnd
wm title . &quot;예제&quot;
label .s1 -text &quot;소스&quot; -fg #700040 -rel raised -bd 2
label .t1 -text &quot;타겟&quot; -fg #700040 -rel raised -bd 2

dnd bindsource .s1 text/plain {return &quot;Hello D&amp;amp;D; World!&quot;}
dnd bindtarget .t1 text/plain &amp;lt;Drop&amp;gt; {showmsg &quot;%A&quot; &quot;%T&quot; &quot;%D&quot;}
bind .s1 &amp;lt;Button-1&amp;gt; {dnd drag %W}

pack .s1 .t1 -side top -ipadx 20 -pady 10

proc showmsg {action type data} {
    tk_messageBox -message &quot;Action:$action Type:$type Data:$data&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/pages/Drag-Drop-%ED%8C%A8%ED%82%A4%EC%A7%80-tkDND</guid>
      <pubDate>Wed, 1 Oct 2025 12:21:26 +0900</pubDate>
    </item>
    <item>
      <title>standalone bgexec</title>
      <link>https://ihmin.tistory.com/702</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl에서 외부 프로그램을 제어시에 복잡한 파이프 개념을 바탕으로 C로 작성해야 하는 불편함이 있습니다. 이런 불편을 덜기위한 커맨드가 있는데 BLT의 bgexec 커맨드입니다. 이 bgexec는 아주 유용한 커맨드로, 단순히 bgexec만을 사용하기 위해 BLT 패키지 전체를 로드해야 하는 불편함이 있어, bgexec 커맨드만을 따로 분리하여 보았습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759213904075&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require bgexec
blt::bgexec ....&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/b3GDhH/dJMb9WL9nIW/qEt1kIEioFHy3kD85uuWy1/bgexec.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;bgexec.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.53MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/cuNYHl/dJMb9M3SV8J/n9ysMPkPiNXDKOrjHfCkBK/bgexec_manual.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;bgexec_manual.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/Tks6R/dJMb9WL9nIY/DZVKC2ZnO8RE3isiflSlvK/bgexec_source.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;bgexec_source.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.33MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/702</guid>
      <comments>https://ihmin.tistory.com/702#entry702comment</comments>
      <pubDate>Tue, 30 Sep 2025 15:33:16 +0900</pubDate>
    </item>
    <item>
      <title>oobgexec1 0.1</title>
      <link>https://ihmin.tistory.com/701</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://wiki.tcl-lang.org/page/Matthias+Hoffmann+-+Tcl-Code-Snippets+-+Misc+-+Bgexec&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wiki.tcl-lang.org/page/Matthias+Hoffmann+-+Tcl-Code-Snippets+-+Misc+-+Bgexec&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TclOO를 이용한 백그라운드 실행중 stdout을 캡쳐하는 클래스입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759212206127&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require TclOO
package require Tcl 8.5
package provide oobgexec1 0.1

oo::class create bgExec {
        self variable objNr
        self method nextObjNr {} {incr objNr}
        self method activeObjects {} {info class instances bgExec}
        self method activeObjectsCount {} {llength [my activeObjects]}; # := vwaitvar
        ###
        # Generische Handler (werden &amp;uuml;ber Fileevent gerufen, m&amp;uuml;ssen also public sein...)
        # $obj wird an den Userhandler &amp;uuml;bergeben, da hier&amp;uuml;ber bei Bedarf zus&amp;auml;tzliche
        # Daten gelesen werden k&amp;ouml;nnen (siehe getInfos).
        # Signatur UserHandler: proc callback {obj type {data &quot;&quot;}}.
        self method onFileEvent {obj chan callback} {
             if {[catch {gets $chan line} result]} {
                $obj cancelTimeout
                catch {uplevel 1 [list {*}$callback $obj error $result]}; # Fehler vor Close melden
                $obj destroy
             } elseif {$result &amp;gt;= 0} {
                catch {uplevel 1 [list {*}$callback $obj data $line]}   ; # Daten vorhanden
             } else {
                catch {uplevel 1 [list {*}$callback $obj nodata]}       ; # keine Daten vorhanden (Idle)
             }
             if {[eof $chan]} {
                $obj cancelTimeout
                catch {uplevel 1 [list {*}$callback $obj eof]}          ; # End-of-File vor Close melden
                $obj destroy
             }
        }
        self method onTimeout {obj callback pids} {
             catch {uplevel 1 [list {*}$callback $obj timeout $pids]}   ; # Timeout vor Close melden
             $obj destroy
        }
        variable pipe cb chan timeoutID userData objNr waitvar
        constructor {pipeline callback args} {
             set options [dict create -timeout 0 -userdata &quot;&quot; -fconf &quot;&quot; -vwaitvar ::bgExecVwaitVar]
             set keys [dict keys $options]
             foreach {arg val} $args {
                  set key [lsearch -glob -nocase -inline $keys $arg*]
                  if {$key ne &quot;&quot;} {
                     dict set options $key $val
                  } else {
                     return -code error &quot;invalid option. Allowed are: $keys.&quot;
                  }
             }
             set pipe $pipeline
             set cb $callback
             set fconf [dict merge {-blocking 0 -buffering line} [dict get $options -fconf]]
             set timeoutID &quot;&quot;
             set waitvar [dict get $options -vwaitvar]; # schon hier, weil im Falle des Scheiterns
             incr $waitvar; # des open der Destruktor aufgerufen wird und dekrementiert!
             set chan [open &quot;| $pipeline 2&amp;gt;@1&quot; r]; # aktuell wieder nur READ-Channel
             fconfigure $chan {*}$fconf
             if {[dict get $options -timeout]} {
                set timeoutID [after [dict get $options -timeout] [list bgExec onTimeout [self] $callback [pid $chan]]]
             }
             set userData [dict get $options -userdata]
             set objNr [bgExec nextObjNr]
             fileevent $chan readable [list bgExec onFileEvent [self] $chan $callback]
        }
        destructor {
            my cancelTimeout
            catch {close $chan}; # falls nicht bereits explizit get&amp;auml;tigt (catch erforderlich?)
            incr $waitvar -1
        }
        method getInfos {} {
            return [list $objNr $chan $pipe $userData $waitvar $timeoutID]
        }
        method cancelTimeout {} {
            if {$timeoutID ne &quot;&quot;} {
               after cancel $timeoutID
            }
        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트는 아래와 같이 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759213029073&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;proc callback {args} {
	puts $args
}

set ::bgExecVwaitVar 0
puts [bgExec new &quot;ping 127.0.0.1&quot; callback -vwaitvar ::bgExecVwaitVar]
vwait ::bgExecVwaitVar&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 결과입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759213064736&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;C:\Temp&amp;gt;tclsh85 oobgexec.tcl
::oo::Obj12
::oo::Obj12 data {}
::oo::Obj12 data {Ping 127.0.0.1 32바이트 데이터 사용:}
::oo::Obj12 data {127.0.0.1의 응답: 바이트=32 시간&amp;lt;1ms TTL=128}
::oo::Obj12 data {127.0.0.1의 응답: 바이트=32 시간&amp;lt;1ms TTL=128}
::oo::Obj12 data {127.0.0.1의 응답: 바이트=32 시간&amp;lt;1ms TTL=128}
::oo::Obj12 data {127.0.0.1의 응답: 바이트=32 시간&amp;lt;1ms TTL=128}
::oo::Obj12 data {}
::oo::Obj12 data {127.0.0.1에 대한 Ping 통계:}
::oo::Obj12 data {    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),}
::oo::Obj12 data {왕복 시간(밀리초):}
::oo::Obj12 data {    최소 = 0ms, 최대 = 0ms, 평균 = 0ms}
::oo::Obj12 nodata
::oo::Obj12 eof&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Tcl &amp;amp; Tk/팁 (Tip)</category>
      <category>bgexec</category>
      <category>Exec</category>
      <category>jobexec</category>
      <category>OO</category>
      <category>Pipe</category>
      <category>tcloo</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/701</guid>
      <comments>https://ihmin.tistory.com/701#entry701comment</comments>
      <pubDate>Tue, 30 Sep 2025 15:18:40 +0900</pubDate>
    </item>
    <item>
      <title>BLT 강좌가 등록 되었습니다.</title>
      <link>https://ihmin.tistory.com/notice/700</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Tk에서 그래프 위젯의 강자라 불리는 BLT에 대한 강좌가 등록 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tcltk.co.kr/pages/%EA%B7%B8%EB%9E%98%ED%94%84-%EC%9C%84%EC%A0%AF%EC%9D%98-%EC%B5%9C%EA%B0%95%EC%9E%90-BLT&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;그래프&amp;nbsp;위젯의&amp;nbsp;최강자&amp;nbsp;BLT&lt;/a&gt;&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/notice/700</guid>
      <pubDate>Tue, 30 Sep 2025 11:02:55 +0900</pubDate>
    </item>
    <item>
      <title>typed_json</title>
      <link>https://ihmin.tistory.com/699</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://github.com/rocketship88/typed-json-tcl&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/rocketship88/typed-json-tcl&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;typed_json은&amp;nbsp;타입&amp;nbsp;정보를&amp;nbsp;완벽하게&amp;nbsp;보존하는&amp;nbsp;순수&amp;nbsp;Tcl&amp;nbsp;기반의&amp;nbsp;JSON&amp;nbsp;파서입니다.&amp;nbsp;tDOM의&amp;nbsp;`-json`&amp;nbsp;옵션과&amp;nbsp;유사하게&amp;nbsp;동작하지만,&amp;nbsp;바이너리&amp;nbsp;확장&amp;nbsp;모듈이&amp;nbsp;필요하지&amp;nbsp;않습니다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지 버전의 코드가 존재합니다.&amp;nbsp;&amp;nbsp; &lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 버전은 dict 구조를 사용하여 속도가 더 빠를 수 있지만, 중복 키를 처리할 수 없습니다.&lt;/li&gt;
&lt;li&gt;두 번째 버전은 오직 리스트 연산만 사용하여 중복 키를 지원하고, tDOM과의 호환성이 더 높습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1758852281226&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Skip built-in tests when sourcing
set no_tests 1
source jsonparser.tcl

# Parse JSON with type information preserved
set data [typed_json::json2dict {{&quot;name&quot;: &quot;Alice&quot;, &quot;age&quot;: 30}}]
puts $data
# Output: OBJECT {name {STRING Alice} age {NUMBER 30}}

# Extract values
puts [typed_json::getValue [typed_json::getPath $data &quot;name&quot;]]
# Output: Alice&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/mQLG8/dJMb9O8r3vs/qV2kwj724lrBEhhTpWKmH1/typed-json-tcl-main.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;typed-json-tcl-main.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.03MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <category>dict</category>
      <category>json</category>
      <category>json2dict</category>
      <category>TCL</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/699</guid>
      <comments>https://ihmin.tistory.com/699#entry699comment</comments>
      <pubDate>Fri, 26 Sep 2025 11:04:58 +0900</pubDate>
    </item>
    <item>
      <title>그래프 위젯의 최강자 BLT</title>
      <link>https://ihmin.tistory.com/pages/%EA%B7%B8%EB%9E%98%ED%94%84-%EC%9C%84%EC%A0%AF%EC%9D%98-%EC%B5%9C%EA%B0%95%EC%9E%90-BLT</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;BLT는 벨 연구소에서 개발되고, 루슨트 테크놀로지에 저작권이 있는, Tk와 더불어 최대의 Tk 확장 라이브러리 세트입니다. Tk의 순수한 기능 확장으로 예전부터 잘 알려져 있습니다. BLT가 무엇의 약자인지는 매뉴얼을 읽어봐도 &quot;원하는 대로 해석하세요&quot;라고만 나와 있으니, &quot;Beautiful Lady and Television&quot;의 약자라고 우겨도 틀리지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;175&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FeTGv/btsQUgj6WI1/pRglkUVIGv1BRRm86MpXLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FeTGv/btsQUgj6WI1/pRglkUVIGv1BRRm86MpXLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FeTGv/btsQUgj6WI1/pRglkUVIGv1BRRm86MpXLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFeTGv%2FbtsQUgj6WI1%2FpRglkUVIGv1BRRm86MpXLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;288&quot; height=&quot;175&quot; data-origin-width=&quot;288&quot; data-origin-height=&quot;175&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BLT의 현재 버전은 2.4z (2002/10/15)이고, [&lt;a href=&quot;https://sourceforge.net/projects/blt/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이곳&lt;/a&gt;] 에서 다운로드할 수 있습니다. Tcl/Tk의 7.5, 7.6, 8.0 이후의 각 버전을 지원합니다. 2.4p부터는 스텁(stub) 메커니즘을 지원하여, 8.2용 BLT는 8.3 이후 버전에서도 사용할 수 있습니다. 반면, 7.* 버전에 대한 지원은 점점 사라지고 있는 듯합니다. &lt;br /&gt;&lt;br /&gt;주요&amp;nbsp;기능으로는&amp;nbsp;다음과&amp;nbsp;같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 2차원 X-Y 그래프&lt;/li&gt;
&lt;li&gt;계층적 리스트박스&lt;/li&gt;
&lt;li&gt;GUI 위젯에 배경 이미지를 붙일 수 있는 확장&lt;/li&gt;
&lt;li&gt;탭이 달린 패널&lt;/li&gt;
&lt;li&gt;&quot;busy&quot; 윈도우&lt;/li&gt;
&lt;li&gt;테이블 형태의 지오메트리 매니저&lt;/li&gt;
&lt;li&gt;윈도우를 Tk 이미지로 캡처하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 기능은 우리 GUI 애플리케이션에 강렬한 외관을 부여해줍니다. 기능이 강력한 만큼 매우 복잡하지만, 함께 제공되는 HTML 문서가 잘 정리되어 있어 이것을 참고하면 쉽게 익숙해질 수 있습니다. 바로 사용해봅시다!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리눅스용 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스에서는&amp;nbsp;익숙한&amp;nbsp;configure&amp;nbsp;&amp;rarr;&amp;nbsp;make&amp;nbsp;&amp;rarr;&amp;nbsp;make&amp;nbsp;install&amp;nbsp;과정으로&amp;nbsp;설치하면&amp;nbsp;됩니다.&amp;nbsp;다만,&amp;nbsp;실행&amp;nbsp;프로그램(bltwish)을&amp;nbsp;만드는&amp;nbsp;것보다&amp;nbsp;공유&amp;nbsp;라이브러리(libBLT24.so)를&amp;nbsp;만들어&amp;nbsp;설치하는&amp;nbsp;쪽이&amp;nbsp;여러모로&amp;nbsp;더&amp;nbsp;편리합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758674986536&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% sh configure
% cd src/shared
% make
# make install
% cd ../../library
% make
# make install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/usr/local에&amp;nbsp;설치한&amp;nbsp;경우,&amp;nbsp;공유&amp;nbsp;라이브러리&amp;nbsp;libBLT24.so는&amp;nbsp;/usr/local/lib/에,&amp;nbsp;초기&amp;nbsp;설정용&amp;nbsp;Tcl&amp;nbsp;스크립트는&amp;nbsp;/usr/local/lib/blt2.4에&amp;nbsp;복사됩니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;윈도우즈용 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows용 BLT는 Tcl/Tk 와 함께 컴파일된 바이너리 버전을 자체 설치 파일 형태로 배포되기 때문에 설치가 매우 간단합니다. 파일을 다운로드하면, 아주 깔끔한 인스톨러가 등장합니다. Tcl/Tk 자체 설치 보다도 더 신경 써서 만든 듯한 설치 화면에서 제작자의 센스를 느낄 수 있습니다. (현재 제공되는 설치 파일은 16비트 윈도우즈 95 만 지원하는것 같습니다. 현재의 윈도우즈 7이나 11에서는 설치가 불가합니다. 리눅스의 설치 방법과 마찬가지로 msys2 환경에서 MinGW 컴파일러를 사용하여 빌드가 가능합니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/crhwcT/dJMb9PzwdE5/nlIH5fmvk8tdyr3ruQkatk/blt24z-for-tcl84.exe?attach=1&amp;amp;knm=tfile.exe&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;blt24z-for-tcl84.exe&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.85MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 위치를 물어보면, 이미 Tcl/Tk 가 설치된 디렉터리(예: `C:\Program Files\TCL`)를 지정하면 됩니다. 물론 다른 디렉터리(예: `C:\Program Files\BLT`)를 지정해도 됩니다. &lt;br /&gt;&lt;br /&gt;설치가 완료되면, `bin` 서브디렉터리 아래에 WISH84.EXE에 BLT가 포함된 인터프리터인 &quot;BLTWISH.EXE&quot;와, load 명령어로 로드할 수 있는 DLL 파일인 &quot;BLT24.DLL&quot;이 생성됩니다. 일반적으로는 BLT24.DLL을 로드해서 사용하는 쪽이 더 편리할 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;BLT 사용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BLT 기능을 사용하는 Tcl 스크립트의 맨 앞에는 다음과 같은 코드를 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758675679211&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름공간(namespace)이 갑자기 등장하지만, 위와 같이 코드를 작성해두면 이후에 BLT의 기능을 사용할 때 이름공간을 신경 쓸 필요가 없어집니다. 그래서 매번 스크립트의 맨 앞부분에 이렇게 적어두는 것이 좋습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;벡터&amp;nbsp;(vector)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터는&amp;nbsp;Tcl의&amp;nbsp;배열과&amp;nbsp;비슷하지만,&amp;nbsp;Tcl의&amp;nbsp;배열에는&amp;nbsp;없는&amp;nbsp;특징이&amp;nbsp;있습니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 인덱스는 0부터 n까지의 숫자이다.&lt;/li&gt;
&lt;li&gt;모든 요소는 부동소수점수(float)이다.&lt;/li&gt;
&lt;li&gt;벡터를&amp;nbsp;명령어처럼&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터를&amp;nbsp;생성할&amp;nbsp;때는&amp;nbsp;vector&amp;nbsp;create를&amp;nbsp;사용합니다.&amp;nbsp;생성된&amp;nbsp;벡터의&amp;nbsp;각&amp;nbsp;요소의&amp;nbsp;초기값은&amp;nbsp;0(0.0)이&amp;nbsp;됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759196593848&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*

# 벡터 x 생성 (0~9)
vector create x(10)
=&amp;gt; ::x
# 벡터 y 생성 (0~9)
vector create y(10)
=&amp;gt; ::y
# 벡터 z 생성 (1~10)
vector create y(1:10)
=&amp;gt; ::z&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터를 삭제할 때는 vector destroy를 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759196607136&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 벡터 x y z 삭제
vector destroy x y z&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터의 각 요소는 인덱스(0~n)를 사용하여 배열처럼 접근할 수 있습니다. 인덱스에 end를 사용하면 마지막 요소를 지정할 수 있습니다. 또한, 콜론(:)을 사용하면 요소의 범위를 지정할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759196621833&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 벡터의 초기화
foreach i {0 1 2 3 4 5 6 7 8 9} {
   set x($i) $i
}
# 첫 번째 요소
puts $x(0)
=&amp;gt; 0.0
# 마지막 요소
puts $x(end)
=&amp;gt; 0.9
# 0~3 범위의 요소
puts $x(0:3)
=&amp;gt; 0.0 0.1 0.2 0.3
# 모든 요소
puts $x(:)
=&amp;gt; 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0
# 1+2번째 요소
puts $x(1+2)
=&amp;gt; 3.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스에 min, max, mean을 사용하면 최소값, 최대값, 평균값을 구할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759196632848&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 벡터의 초기화
foreach i {0 1 2 3 4 5 6 7 8 9} {
   set x($i) $i
}
# 최소값
puts $x(min)
=&amp;gt; 0.0
# 최대값
puts $x(max)
=&amp;gt; 9.0
# 평균값
puts $x(mean)
=&amp;gt; 4.5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적으로 벡터를 생성할 수도 있습니다. 벡터 생성 시 요소의 개수를 지정하지 않은 대신 &quot;++end&quot;를 사용해서 동적으로 요소를 할당합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759196643864&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 동적 벡터 d 생성
vector create d
# 벡터 초기화
foreach i {0 1 2 3 4 5 6 7 8 9} {
    set d(++end) $i
}
# 모든 요소 출력
puts $d(:)
=&amp;gt; 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터를 생성하면 커맨드로도 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759196659089&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 벡터 z를 생성
vector create z
# 요소 초기화
z set {9 8 7 6 5 4 3 2 1 0}
# 요소 개수 확인
z length
=&amp;gt; 10
# 요소를 오름차순 또는 내림차순 정렬
z sort
z sort -reverse
# 범위의 요소 반환
z range 0 end
=&amp;gt; 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0
# 검색한 요소의 인덱스 반환
z search 5.0
=&amp;gt; 5
# 요소 추가
z append {10.0 11.0}
# 모든 요소에 1.0을 더하기
z expr { z + 1 }
# -5에서 5까지 1씩 증가시켜 요소 설정
z seq -5 5 1
# 정규화
z normalize
# 데이터를 보간(보충)
z populate z2 10
# 복제
z dup zz
# 요소 삭제
z delete 1 2
# 요소 병합
z merge v1 v2
# 난수 설정
z random
# 요소를 시프트
z offset -1
# 벡터를 Tcl 배열에 매핑
z variable ary&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 벡터는 아래에서 설명할 그래프 그리기에 리스트 데이타 대신에 사용할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;선 그래프 그리기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BLT에서 제공하는 그래프는 모두 X-Y 2차원 그래프입니다.&amp;nbsp; 그래프의 종류로는 `graph`, `barchart`, `stripchart`가 있습니다. 하지만 기본 사용법은 거의 동일하므로 여기서는 대표적으로 `graph`를 사용합니다.&amp;nbsp; `graph`, `stripchart`는 선 그래프, `barchart`는 막대그래프입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758675920499&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . &quot;BLT 샘플 1&quot;

set temperature {5 10 15 20 25 30 35 40 45}
set di {81.2 72.5 43.4 5.6 18.2 60.9 98.2 99.9 99.8}

pack [set g [graph .g -plotbackground black]]
$g configure -title &quot;온도와 사람의 불쾌지수 관계&quot;

$g element create line1 -xdata $temperature -ydata $di
$g element configure line1 -label {2001.7 조사} \
  -symbol square -pixels 4 -color &quot;#ffcc00&quot; -fill &quot;#800000&quot; \
  -outline &quot;#ff0000&quot; -outlinewidth 1 \
  -dashes {2 4 2} -linewidth 2 -trace increasing
# symbol: square, circle, diamond, plus, cross, splus, scross, triangle, &quot;&quot;
$g element show
$g axis configure x -title 온도
$g axis configure y -title 불쾌지수

# 마우스 조작으로 확대, 축소
bind $g &amp;lt;ButtonPress-1&amp;gt; {
    %W axis configure x -min [%W axis invtransform x %x]
    %W axis configure y -min [%W axis invtransform y %y]
}
# 원래대로 되돌리기
bind $g &amp;lt;ButtonPress-3&amp;gt; {
    %W axis configure x -min {}
    %W axis configure y -min {}
}
$g legend configure -position right -relief groove -font fixed -fg blue
$g crosshairs configure -hide no -color red -dashes {2 2} -linewidth 2
Blt_Crosshairs $g
$g grid configure -hide no -dashes { 2 2 }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4d6Ia/btsQMlS7ujX/nKRBD7OWXdfOel88bdD3nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4d6Ia/btsQMlS7ujX/nKRBD7OWXdfOel88bdD3nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4d6Ia/btsQMlS7ujX/nKRBD7OWXdfOel88bdD3nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4d6Ia%2FbtsQMlS7ujX%2FnKRBD7OWXdfOel88bdD3nK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;482&quot; height=&quot;416&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음으로 X축과 Y축 데이터를 준비합니다. 기본적으로 두 축 모두 숫자 축입니다. 아래 예시처럼 각각 숫자로 이루어진 두 개의 리스트를 준비해도 되고, 위에서 설명한 벡터(vector)를 사용할 수도 있습니다.&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;여기서는 &quot;기온(섭씨)&quot;과 &quot;불쾌지수(%)&quot; 데이터를 예로 들었습니다. 40도에서 45도로 갈 때 불쾌지수가 줄어드는 것은, &amp;ldquo;그 사이에 깨달음의 경지에 도달해서 불도 시원하게 느껴진다&amp;rdquo;는 이상한 답변을 한 사람이 한 명 있었기 때문입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758676261932&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set temperature {5 10 15 20 25 30 35 40 45}
set di {81.2 72.5 43.4 5.6 18.2 60.9 98.2 99.9 99.8}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 그래프 위젯을 생성하고 Tk 위젯처럼 `pack` 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758676355212&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;graph .g -plotbackground black
pack .g
.g configure -title &quot;온도와 사람의 불쾌지수 관계&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 그래프 위젯(.g)에 데이터를 붙여서 선그래프로 만듭니다. `element create` 명령을 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758676406669&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.g element create line1 -xdata $temperature -ydata $di&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선(데이터 시리즈)에 대한 각종 옵션을 `element configure`로 설정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758676444589&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.g element configure line1 -label {1999.7 조사} \
  -symbol square -color red -dashes {2 4 2} -linewidth 2
.g element show&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-label : 범례에 표시될 이름&lt;/li&gt;
&lt;li&gt;-symbol : 데이터 점의 모양&lt;/li&gt;
&lt;li&gt;-color : 선 색상&lt;/li&gt;
&lt;li&gt;-dashes : 선의 점선 패턴&lt;/li&gt;
&lt;li&gt;-linewidth&amp;nbsp;:&amp;nbsp;선&amp;nbsp;두께&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 좌표축 설정을 하고&lt;/p&gt;
&lt;pre id=&quot;code_1758676570934&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.g axis configure x -title 온도
.g axis configure y -title 불쾌지수&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;`axis configure`의 -min, -max 옵션을 이용하면 그래프를 줌인/줌아웃 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758676629045&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 왼쪽 클릭: 확대
bind .g &amp;lt;ButtonPress-1&amp;gt; { 
    %W axis configure x -min [%W axis invtransform x %x] 
    %W axis configure y -min [%W axis invtransform y %y] 
}
# 오른쪽 클릭: 원래대로 복원
bind .g &amp;lt;ButtonPress-3&amp;gt; { 
    %W axis configure x -min {}
    %W axis configure y -min {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범례, 크로스헤어, 격자선 등도 세밀하게 설정할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758676654957&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.g legend configure -position right -relief groove -font fixed -fg blue
.g crosshairs configure -hide no -color red -dashes {2 2} -linewidth 2
Blt_Crosshairs .g
.g grid configure -hide no -dashes { 2 2 }&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;계층 구조 리스트박스 (Hierarchical Listbox)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층 구조 리스트박스란, 쉽게 말해 Windows의 탐색기 왼쪽 부분(트리 구조 폴더 리스트)과 같은 GUI 위젯 입니다. BLT의 hierbox 위젯을 사용하면, 일반적인 Tk 위젯처럼 동일하게 생성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 hierbox 위젯은 BLT 2.4w 버전에서 완전 상위 호환인 treeview 위젯이 등장하면서,&amp;nbsp; 현재는 향후 폐지 예정으로 간주됩니다.&amp;nbsp; 최신 프로젝트에서는 treeview 위젯 사용을 권장합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758677210446&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . &quot;BLT 샘플 2&quot;

entry .ea -state disabled
set f [frame .fa -rel groove]
set h [hierbox $f.h -yscrollcommand &quot;$f.scrv set&quot; -height 200]
scrollbar $f.scrv -orient vertical -command &quot;$f.h yview&quot;
grid $f.h -row 1 -column 1
grid $f.scrv -row 1 -column 2 -sticky ns
foreach e {ea fa} {pack .$e -side top -fill x}

$h configure -separator {::}
foreach a {::java ::javax ::javax::swing ::java::io ::java::net ::javax::swing::table
           ::javax::naming ::javax::naming::directory} {
    $h insert end $a
}
bind $h &amp;lt;Double-Button-1&amp;gt; {
    if {&quot;[set i [%W curselection]]&quot; != &quot;&quot;} {
        .ea configure -state normal
        .ea delete 0 end
        .ea insert end &quot;[%W get $i] : [%W get -full $i]&quot;
        .ea configure -state disabled
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;219&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsJiSU/btsQLAcdZ3S/TrZNHCoUWTKH6HXkE145l1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsJiSU/btsQLAcdZ3S/TrZNHCoUWTKH6HXkE145l1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsJiSU/btsQLAcdZ3S/TrZNHCoUWTKH6HXkE145l1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsJiSU%2FbtsQLAcdZ3S%2FTrZNHCoUWTKH6HXkE145l1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;219&quot; height=&quot;255&quot; data-origin-width=&quot;219&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hierbox 커맨드는 일반 Tk 위젯처럼 사용하고, insert, delete, curselection, get 등 주요 조작법도 listbox와 거의 동일합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758677270545&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;hierbox .h -yscrollcommand {.scrv set} -height 200
scrollbar .scrv -orient vertical -command {.h yview}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층 구조(트리)를 만들려면, 먼저 `configure`의 `-separator` 옵션으로 계층 구분 문자를 지정합니다. 예를 들어, &quot;::java::awt&quot;라는 아이템은 루트 아래 &quot;java&quot; 폴더, 그 아래 &quot;awt&quot; 폴더가 생기는 구조를 의미합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758677324744&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.h configure -separator {::}
foreach a {::java ::java::awt ::java::io ::java::net ::java::awt::event} {
    .h insert end $a
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;아래와 같이 트리 아이템을 더블 클릭시 현재 선택된 노드의 풀 패스를 표시합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;`get -full` 옵션을 사용하면, 트리의 전체 경로가 반환됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758678089609&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bind $h &amp;lt;Double-Button-1&amp;gt; {
    if {&quot;[set i [%W curselection]]&quot; != &quot;&quot;} {
        .ea configure -state normal
        .ea delete 0 end
        .ea insert end &quot;[%W get $i] : [%W get -full $i]&quot;
        .ea configure -state disabled
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;막대 그래프&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;BLT의 그래프에는 정말 많은 옵션이 있습니다. 그것들을 전부 나열하고 설명하다 보면 중간에 질려버릴 수 있기에 생략하고, 선 그래프 부분에서 소개했던 예제를 다시 정리해서 이번에는 처음부터 막대 그래프를 그려보겠습니다. &lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759122574165&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . &quot;BLT 샘플&quot;

set xdata {1 2 3 4 5}
set ydata {65 30 40 90 55}

barchart .sc \
 -plotbackground &quot;#c0c0c0&quot; -plotrelief sunken \
 -plotborderwidth 2 -background &quot;#808080&quot; \
 -relief groove -bd 2 -title &quot;My Brain is Compact&quot;

.sc element create ELEMENT1 \
  -xdata $xdata -ydata $ydata -label &quot;This is the Legend&quot; -fg &quot;#700040&quot;

proc getSubjectByID {sc value args} {
    set subjects {dummy 국어 수학 물리 지리 영어}
    return [lindex $subjects $value]
}

.sc axis configure x -color white -command &quot;getSubjectByID&quot; \
        -title 교과 -titlecolor &quot;#c0c0c0&quot;

.sc axis configure y -color white -min 0 -max 100

.sc legend configure -position right -relief groove -font 7x14 -fg #000060

.sc crosshairs configure -hide no -color black -linewidth 2 -dashes &quot;&quot;
Blt_Crosshairs .sc

.sc grid configure -hide no -color &quot;#808080&quot; -dashes {1 4 1}

image create photo Image1 -file copy.gif
for {set i 0} {$i&amp;lt;[llength $xdata]} {incr i} {
    set lab [label .sc.lab$i -image Image1]
    .sc marker create window \
        -coords [list [lindex $xdata $i] [expr [lindex $ydata $i]-5] ] \
        -anchor n -window $lab
}
pack .sc -side top
button .cmda -text 닫기 -command exit
pack .cmda -anc e -padx 4 -pady 4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;457&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5Ng1V/btsQVJZQgYP/cKNIRiK6yKdaRKBh9D0nrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5Ng1V/btsQVJZQgYP/cKNIRiK6yKdaRKBh9D0nrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5Ng1V/btsQVJZQgYP/cKNIRiK6yKdaRKBh9D0nrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5Ng1V%2FbtsQVJZQgYP%2FcKNIRiK6yKdaRKBh9D0nrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;482&quot; height=&quot;457&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;457&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;먼저 BLT 라이브러리를 불러옵니다. &lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759122595102&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;데이터는 아래와 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 47.2093%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.88372%;&quot;&gt;국어&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 9.5349%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;수학&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.06977%;&quot;&gt;물리&lt;/td&gt;
&lt;td style=&quot;width: 9.3023%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;지리&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 9.4186%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;영어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.88372%;&quot;&gt;65&amp;nbsp;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 9.5349%;&quot;&gt;30&amp;nbsp;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 9.06977%;&quot;&gt;40&lt;/td&gt;
&lt;td style=&quot;width: 9.3023%;&quot;&gt;90&lt;/td&gt;
&lt;td style=&quot;width: 9.4186%;&quot;&gt;55&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;점수 참 형편 없네요 ㅎㅎ 이처럼 한쪽 축이 숫자 축이 아닌 경우엔 약간의 트릭이 필요합니다. 일단 데이터는 아래와 같이 작성해둡니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759122670133&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set xdata {1 2 3 4 5}
set ydata {65 30 40 90 55}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;먼저 `barchart` 명령으로 막대 그래프를 그릴 영역을 일반 Tk 위젯과 마찬가지로 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759122691350&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;barchart .sc \
 -plotbackground &quot;#c0c0c0&quot; -plotrelief sunken -plotborderwidth 2 \
 -background &quot;#808080&quot; -relief groove -bd 2 \
 -title &quot;My Brain is Compact&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이처럼 생성 시에 모든 옵션을 정의할 수도 있지만, 예를 들면&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759122709254&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;barchart .sc
# ...
.sc configure -plotbackground &quot;#c0c0c0&quot; \
              -plotrelief sunken \
              # ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이런 식으로 나중에 `configure` 서브커맨드를 사용해서 옵션을 여러 번 추가하거나 변경할 수 있습니다. 즉 일반 Tk 위젯처럼 `cget` &amp;amp; `configure`로 조작할 수 있다는 얘기입니다. 참고로 `-plotbackground`, `-plotrelief`, `-plotborderwidth`는 그래프의 그려지는 범위의 색상이나 테두리 스타일을 지정하는 옵션이고, `-background(-bg)`, `-relief`, `-borderwidth(-bd)`는 그 바깥 영역의 스타일을 지정하는 옵션입니다. 뭐, 직접 써보면 바로 알 수 있으니, 여기서 자세한 설명은 생략합니다. &lt;br /&gt;&lt;br /&gt;다음으로&amp;nbsp;그래프의&amp;nbsp;&quot;데이터&amp;nbsp;시리즈&quot;를&amp;nbsp;만듭니다.&amp;nbsp;데이터&amp;nbsp;시리즈란,&amp;nbsp;쉽게&amp;nbsp;말해&amp;nbsp;그래프의&amp;nbsp;데이터를&amp;nbsp;표현하는&amp;nbsp;것이고,&amp;nbsp;막대&amp;nbsp;그래프라면&amp;nbsp;막대,&amp;nbsp;선&amp;nbsp;그래프라면&amp;nbsp;선입니다.&amp;nbsp;아래의&amp;nbsp;`ELEMENT1`처럼&amp;nbsp;적당한&amp;nbsp;이름을&amp;nbsp;정해&amp;nbsp;`element&amp;nbsp;create`&amp;nbsp;서브커맨드로&amp;nbsp;생성합니다. &lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759122787853&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.sc element create ELEMENT1 \
  -xdata $xdata -ydata $ydata -label &quot;This is the Legend&quot; -fg &quot;#700040&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 데이터 -xdata, -ydata에 데이터(숫자 리스트)를 지정함으로써, 실제로 그래프에 반영됩니다. X축 데이터는 &quot;국어&quot;, &quot;수학&quot;과 같은 숫자가 아닌 값을 넣으면 안되기에 임시로 $xdata로 {1 2 3 4 5} 로 넣어 두었습니다.&lt;br /&gt;&lt;br /&gt;참고로&amp;nbsp;이&amp;nbsp;element도,&amp;nbsp;일단&amp;nbsp;element&amp;nbsp;create&amp;nbsp;서브커맨드로&amp;nbsp;만든&amp;nbsp;후에,&amp;nbsp;&quot;element&amp;nbsp;configure&quot;&amp;nbsp;서브커맨드를&amp;nbsp;사용해서&lt;/p&gt;
&lt;pre id=&quot;code_1759123052254&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.sc element configure ELEMENT1 -fg &quot;#700040&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처럼 설정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게&amp;nbsp;옵션을&amp;nbsp;추가하거나&amp;nbsp;변경할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이후&amp;nbsp;나오는&amp;nbsp;axis,&amp;nbsp;crosshairs,&amp;nbsp;grid,&amp;nbsp;marker&amp;nbsp;등도&amp;nbsp;모두&amp;nbsp;이&amp;nbsp;element와&amp;nbsp;같은&amp;nbsp;방식으로,&amp;nbsp;단지&amp;nbsp;옵션의&amp;nbsp;종류만&amp;nbsp;다릅니다. &lt;br /&gt;&lt;br /&gt;다음은 X축을 셋팅해 봅니다. 여기서는 앞서 사용한 {1 2 3 4 5} 를 {국어 수학 물리 지리 영어} 로 바꿔주는 처리를 하고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123077832&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;proc getSubjectByID {sc value args} {
    set subjects {dummy 국어 수학 물리 지리 영어}
    return [lindex $subjects $value]
}

.sc axis configure x \
  -color white -command &quot;getSubjectByID&quot; \
  -title Subject -titlecolor &quot;#c0c0c0&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axis는 기본적으로 &quot;x&quot;와 &quot;y&quot;가 이미 생성되어 있기 때문에 &quot;axis create&quot; 같은 명령을 쓸 필요 없이 바로 &quot;axis configure x&quot;로 옵션을 지정할 수 있습니다. 여기서 중요한 점은 -command &quot;getSubjectByID&quot; 옵션입니다. -command를 지정하면, X축에 -xdata로 전달한 숫자 배열 대신 이 명령이 호출되어 반환된 문자열이 표시됩니다. 이 명령 뒤에는 barchart 컴포넌트의 위젯(여기서는 .sc)과 현재의 값이 인자로 자동으로 붙습니다. 이렇게 하면 X축에는 {1 2 3 4 5} 대신 {국어 수학 물리 지리 영어} 가 표시됩니다. &lt;br /&gt;&lt;br /&gt;Y축도 방법도 동일합니다. 여기서는 -min과 -max를 지정해서 그려지는 그래프의 값 범위를 지정하고 있습니다. -min과 -max를 넓히거나 좁히면 줌 인/아웃 기능을 쉽게 넣을 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123184767&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.sc axis configure y -color white -min 0 -max 100&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;legend(레전드)는 &quot;범례&quot;를 의미합니다. 범례에 표시되는 각 데이터 시리즈의 설명은 element configure 서브커맨드의 -label 옵션으로 지정합니다. legend configure 서브커맨드는 범례를 표시하는 직사각형 영역의 꾸밈 방식을 지정하는 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123220904&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.sc legend configure \
  -position right -relief groove -font 7x14 -fg blue&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크로스헤어(십자선)는 이전 페이지에서도 나왔듯이, 마우스가 그래프 위를 움직이면 거기에 따라 십자 형태로 움직이는 교차선입니다. 크로스헤어는 기본적으로 &quot;표시하지 않음&quot;이기 때문에, 표시하려면 &quot;-hide&quot; 옵션을 &quot;no&quot;로 해야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759123249240&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.sc crosshairs configure \
  -hide no -color black -linewidth 2 -dashes &quot;&quot;
Blt_Crosshairs .sc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한&amp;nbsp;실제로&amp;nbsp;크로스헤어를&amp;nbsp;표시하려면&amp;nbsp;위와&amp;nbsp;같이&amp;nbsp;Blt_Crosshairs라는&amp;nbsp;하위&amp;nbsp;라이브러리&amp;nbsp;프로시저를&amp;nbsp;호출해야&amp;nbsp;합니다. &lt;br /&gt;&lt;br /&gt;그리드는 페인트 툴이나 드로잉 툴에서 익숙한 격자무늬입니다. 이것도 기본적으로 표시되지 않으니, 역시 &quot;-hide no&quot;로 해야 표시됩니다. 크로스헤어 옵션에도 있었던 -dashes는 점선의 &quot;끊김 정도&quot;를 지정하는 것입니다. 말로 설명하기 어렵기 때문에 적당히 값을 바꿔서 시험해 보세요. -dashes &quot;&quot;로 하면 실선으로 표시되고, 기본값도 실선입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123282440&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.sc grid configure \
  -hide no -color &quot;#808080&quot; -dashes {1 4 1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 중요한 마커가 남았는데, 이는 감각적으로는 캔버스 위젯(canvas)처럼 그래프 영역 내에 사각형, 원 같은 도형, 텍스트, 이미지, 그리고 다른 Tk 컴포넌트를 배치할 수 있습니다. 아래 예시에서는 각 막대의 맨 위에 이미지 데이터를 붙인 라벨을 올리고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123308199&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;image create photo Image1 -file copy.gif
for {set i 0} {$i&amp;lt;[llength $xdata]} {incr i} {
    set lab [label .sc.lab$i -image Image1]
    .sc marker create window \
        -coords [list [lindex $xdata $i] [lindex $ydata $i]] \
        -anchor n -window $lab
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 이 .sc를 pack 등으로 배치하면 막대 그래프가 완성됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123318991&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pack .sc -side top
button .cmda -text Close -command exit
pack .cmda&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tk 위젯에 배경 이미지 붙이기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BLT에서는 라벨, 버튼, 체크 버튼, 라디오 버튼, 프레임, 스크롤바, 탑레벨 위젯의 배경에 photo 이미지로 만든 이미지를 배경 이미지로 셋팅 할 수 있도록 확장되어 있습니다. 사용 방법은 간단하게, -tile 옵션에 이미지 이름을 지정해주기만 하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123628712&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . {BLT 샘플}

image create photo Image1 -file bg.gif
frame .f -tile Image1
message .f.ma -text {Hello. This is a sample of tile-extended widgets.} \
  -fg #700040 -font {Helvetica 12 normal}
button .f.cmda -text OK -command exit -tile Image1
pack .f.ma   -side top -padx 4 -pady 4
pack .f.cmda -side top -ipadx 10 -padx 4 -pady 4
pack .f&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기능을 효과적으로 사용하면, 여러분의 애플리케이션이 보기좋게 변신됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;138&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcxbu1/btsQVFQQQpn/IQFIsJ7CNTidkPrJkpjbC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcxbu1/btsQVFQQQpn/IQFIsJ7CNTidkPrJkpjbC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcxbu1/btsQVFQQQpn/IQFIsJ7CNTidkPrJkpjbC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcxbu1%2FbtsQVFQQQpn%2FIQFIsJ7CNTidkPrJkpjbC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;138&quot; height=&quot;166&quot; data-origin-width=&quot;138&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스냅샷 기능&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BLT에는 Tcl/Tk 윈도우의 스냅샷을 찍어서, Tk의 photo 이미지로 복사하는 기능이 있습니다. 캔버스에 그린 도형을 비트맵으로 저장할 수 있어 매우 편리합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123770577&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

canvas .can -bg white
.can create polygon {20 30 40 80 60 90 90 75 50 40 20 30} \
  -outline yellow -fill red -tag TagPolygon
.can create oval 100 80 130 110 -outline blue -fill cyan -width 5 -tag TagOval
foreach t {TagPolygon TagOval} {
    .can bind $t &amp;lt;Button-1&amp;gt; { set StartX %x ; set StartY %y }
    .can bind $t &amp;lt;Button1-Motion&amp;gt; &quot;
      set dx \[expr %x-\$StartX\]; set dy \[expr %y-\$StartY\]
      set StartX %x; set StartY %y; %W move $t \$dx \$dy&quot;
}
pack .can
bind .can &amp;lt;Button-3&amp;gt; {
    image create photo Image1
    winop snap .can Image1
    Image1 write output.gif -format gif
    image delete Image1
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스냅샷을 찍는 것은 winop snap이라는 명령어로, 인자로 찍고 싶은 윈도우와 저장할 photo 이미지의 이름을 지정해주면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759123748473&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;winop snap .can Image1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfGSYF/btsQR2Ayh41/3L1JBbUbKnjKI71BPC5G1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfGSYF/btsQR2Ayh41/3L1JBbUbKnjKI71BPC5G1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfGSYF/btsQR2Ayh41/3L1JBbUbKnjKI71BPC5G1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfGSYF%2FbtsQR2Ayh41%2F3L1JBbUbKnjKI71BPC5G1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;549&quot; height=&quot;508&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 이미지는 위의 코드로 생성된 GIF 이미지 파일입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;탭셋(Tabset)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탭셋은 탭을 붙일 수 있는 GUI 위젯입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crvvck/btsQVsc8Ia1/egJTwXvwyziUDESrmQSREK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crvvck/btsQVsc8Ia1/egJTwXvwyziUDESrmQSREK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crvvck/btsQVsc8Ia1/egJTwXvwyziUDESrmQSREK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcrvvck%2FbtsQVsc8Ia1%2FegJTwXvwyziUDESrmQSREK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;341&quot; height=&quot;358&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;탭셋은 위의 이미지와 같이 탭을 클릭하면 그 탭에 연결된 윈도우를 보여주는 기능입니다. 이런 GUI 위젯을 Tcl/Tk에서 사용할 수 있게 해주는 확장은 여러 종류가 있지만, BLT의 탭셋도 꽤 쓰기 쉽고 유용한 위젯이라고 생각됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759125068148&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . &quot;BLT 샘플&quot;
pack [set ta [tabset .ta]] -side top

$ta insert end tab1 -text &quot;그림&quot;
frame $ta.f1
set can [canvas $ta.f1.can -width 200 -height 200 -bg white]
bind $can &amp;lt;Button-1&amp;gt; { set sx %x; set sy %y }
bind $can &amp;lt;Button1-Motion&amp;gt; {
  set colorSpec [format &quot;#%%02x%%02x%%02x&quot; $Color(RED) $Color(GREEN) $Color(BLUE)]
  %W create line $sx $sy %x %y -fill $colorSpec -width $LineWidth
  set sx %x; set sy %y
}
pack $can
$ta tab configure tab1 -window $ta.f1

$ta insert end tab2 -text &quot;선의 설정&quot;
set fa [frame $ta.f2]
set LineWidth 4
set scaa [scale $fa.scaa -from 1 -to 10 \
  -variable LineWidth -length 140 -ori h -label &quot;선의 굵기&quot;]
pack $scaa -side top -anc w
foreach e {red green blue} {
  set Color([string toupper $e]) 128
  set sca$e [scale $fa.sca$e -from 0 -to 255 \
    -variable Color([string toupper $e]) -ori h -label [string toupper $e]]
  pack [set sca$e] -side top -anc w
}
$ta tab configure tab2 -window $ta.f2

$ta insert end tab3 -text &quot;파일&quot;
set fa [frame $ta.f3]
set lm [label $fa.la -text &quot;출력 모드&quot;]
set fm [frame $fa.fm -rel groove -bd 2]
set modeStrings {컬러 그레이 이진}
set modes {color gray mono}
set OutputColorMode color
foreach e {0 1 2} {
  set r [radiobutton $fm.rad$e -variable OutputColorMode \
         -text [lindex $modeStrings $e] -value [lindex $modes $e]]
  pack $r -side left -padx 4
}
set lf [label $fa.lf -text &quot;출력 파일명&quot;]
set ff [frame $fa.ff -rel groove -bd 2]
entry $ff.ea -width 30 -textvariable OutputFileName
button $ff.ba -text &quot;찾아보기...&quot; -command {
  if {&quot;[set a [tk_getSaveFile -title &quot;출력 파일명 지정&quot;]]&quot; != &quot;&quot;} {
    set OutputFileName $a
  }
}
pack $ff.ea $ff.ba -side left -padx 4
set b [button $fa.b -text &quot;출력&quot; -command {
  if {&quot;$OutputFileName&quot; == &quot;&quot;} {
    tk_messageBox -message &quot;파일을 지정해 주세요.&quot;
  } else {
    $can postscript -file $OutputFileName -colormode $OutputColorMode
    tk_messageBox -message \
&quot;출력 완료: $OutputFileName ([file size $OutputFileName]bytes)&quot;
  }
}]
pack $lm $fm $lf $ff $b -side top -anc w
$ta tab configure tab3 -window $ta.f3

pack [set ba [button .ba -text &quot;닫기&quot; -command exit]] \
 -padx 5 -pady 5 -anc e -side top&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법은 매우 간단합니다. BLT 라이브러리를 로드한 뒤, tabset이라는 명령어로 일반 Tk 위젯처럼 이름을 지정해서 생성합니다. tabset의 옵션은 frame 명령어의 옵션과 비슷해서, -relief, -borderwidth, -width 등을 지정할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759125089789&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pack [set ta [tabset .ta -relief groove -borderwidth 2]] -side top&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로,&amp;nbsp;각&amp;nbsp;탭을&amp;nbsp;클릭했을&amp;nbsp;때&amp;nbsp;표시될&amp;nbsp;GUI를&amp;nbsp;만듭니다.&amp;nbsp;이것은&amp;nbsp;탭별로&amp;nbsp;하나씩&amp;nbsp;frame을&amp;nbsp;만들고,&amp;nbsp;그&amp;nbsp;안에&amp;nbsp;각&amp;nbsp;탭의&amp;nbsp;GUI를&amp;nbsp;넣으면&amp;nbsp;편리합니다.&amp;nbsp;여기서&amp;nbsp;추가할&amp;nbsp;frame&amp;nbsp;등&amp;nbsp;위젯은&amp;nbsp;반드시&amp;nbsp;tabset&amp;nbsp;위젯(여기서는&amp;nbsp;.ta)의&amp;nbsp;자식&amp;nbsp;위젯이어야&amp;nbsp;합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759125106805&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;frame .ta.f1
# ... 이하에 GUI 위젯을 추가
frame .ta.f2
# ... 이하에 GUI 위젯을 추가
# ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 탭에 표시될 GUI를 만들었으면, 탭과 그 GUI를 &quot;연결&quot;합니다. 이는 아래와 같이 tabset 위젯의 insert 서브커맨드를 사용해 tabset에 탭을 추가하고, 탭의 제목 부분은 -text 옵션으로, 탭 GUI의 &quot;내용&quot;이 될 위젯을 -window 옵션으로 지정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759125126565&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ta insert end tab1 -text &quot;그림&quot;
$ta tab configure tab1 -window $ta.f1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tab1이나 tab2 같은 이름은 각 탭마다 자유롭게 붙일 수 있는 고유한 &quot;이름&quot;입니다. 이렇게 지정된 이름은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;tab configure 서브커맨드를 사용하여 &lt;/span&gt;각 탭을 제어하는데 사용 됩니다. 이렇게 &quot;그림&quot; 탭을 클릭하면, 프레임 .ta.tab1에 지정된 GUI가 표시되게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br9hGK/btsQVlrI5Ei/wBK7gNog6zSNxklsG71nB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br9hGK/btsQVlrI5Ei/wBK7gNog6zSNxklsG71nB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br9hGK/btsQVlrI5Ei/wBK7gNog6zSNxklsG71nB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr9hGK%2FbtsQVlrI5Ei%2FwBK7gNog6zSNxklsG71nB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;341&quot; height=&quot;358&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트리뷰(Treeview)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BLT 버전 2.4w부터 트리뷰(treeview) 위젯이 추가되었습니다. 이것은 2.4o에서 2.4v까지 존재했던 계층구조테이블(hiertable)의 상위 호환으로, 왼쪽 절반은 계층형 리스트박스와 같은 트리, 오른쪽 절반은 테이블 형식의 정보 표시 영역을 제공합니다. 오른쪽은 워크시트처럼 직접 키보드 입력으로 값을 편집할 수는 없지만, 그래도 상당히 강력한 위젯입니다. 2.4w에서 이 treeview가 등장함에 따라, hierbox 위젯과 hiertable 위젯은 호환성을 위해서만 남겨놓은 상태 입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759126038975&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . &quot;BLT 샘플(treeview)&quot;
treeview .ta -separator / -width 400 -height 160
set paths {/korea /korea/taejeon /korea/boondang 
           /korea/boondang/pankyo /korea/busan /china}
set labels {한국지사 대전지점 분당지점 판교출장소 부산지점 중국지사}
for {set i 0} {$i&amp;lt;6} {incr i} {
    set ids([lindex $paths $i]) \
      [.ta insert end [lindex $paths $i] \
       -label [lindex $labels $i] ]
}
.ta entry configure $ids(/china) -foreground red

.ta column insert end &quot;emps&quot; -text 직원수
.ta column insert end &quot;equips&quot; -text 설비대수
.ta column insert end &quot;start_date&quot; -text 시작연월
.ta entry configure $ids(/korea/boondang) \
  -data {emps 45 equips 130 start_date 200010}
.ta selection set $ids(/korea/taejeon)
.ta open $ids(/korea)

bind .ta &amp;lt;Double-Button-1&amp;gt; {
    set id [%W curselection]
    set path [%W get -full $id]
    set label [%W entry cget $id -label]
    tk_messageBox -message &quot;/$path ($label) 이(가) 클릭되었습니다.&quot;
}
pack .ta&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v3sKX/btsQS1nQ6yz/dKVQFCEKnGLv6COoxIDno0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v3sKX/btsQS1nQ6yz/dKVQFCEKnGLv6COoxIDno0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v3sKX/btsQS1nQ6yz/dKVQFCEKnGLv6COoxIDno0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv3sKX%2FbtsQS1nQ6yz%2FdKVQFCEKnGLv6COoxIDno0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;402&quot; height=&quot;192&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리뷰는&amp;nbsp;treeview&amp;nbsp;명령어로&amp;nbsp;만듭니다.&amp;nbsp;일반&amp;nbsp;Tk&amp;nbsp;위젯과&amp;nbsp;마찬가지로&amp;nbsp;뒤에&amp;nbsp;옵션을&amp;nbsp;붙일&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759126055600&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;treeview .ta -separator / -width 400 -height 160&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트박스처럼 스크롤바와 함께 사용할 경우가 많으리라 생각합니다. 하지만 가장 중요한 옵션은 -separator로, 트리에 표시할 아이템의 계층을 나타내는 경로(Path)의 구분 문자를 지정합니다. 여기서는 &quot;/&quot;를 사용했지만, &quot;.&quot;이나 &quot;::&quot; 등도 많이 씁니다. 트리에 아이템을 추가하려면 insert 서브커맨드를 사용합니다. 이것은 리스트박스의 insert 명령과 거의 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759126110017&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set paths {/korea /korea/taejeon /korea/boondang 
           /korea/boondang/pankyo /korea/busan /china}
set labels {한국지사 대전지점 분당지점 판교출장소 부산지점 중국지사}
for {set i 0} {$i&amp;lt;6} {incr i} {
    set ids([lindex $paths $i]) \
      [.ta insert end [lindex $paths $i] \
       -label [lindex $labels $i] ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;end 위치에는 새로운 아이템을 추가할 위치를 지정하는 인덱스나 키워드를 사용할 수 있습니다. end도 그중 하나입니다. 자세한 것은 매뉴얼을 참고하세요. 그리고 그 뒤에 &quot;/korea/boondang/pankyo&quot; 와 같은 경로를 지정하고, 실제로 트리에 표시되는 문자열은 -label로 지정합니다. 이 명령은 아이템의 ID(정수) 를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번 추가한 아이템의 설정을 변경하려면 entry configure 서브커맨드를 사용합니다. 예를 들어, 경로 &quot;/china&quot;의 라벨을 빨간색으로 바꾸려면,&lt;/p&gt;
&lt;pre id=&quot;code_1759126377936&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.ta entry configure $ids(/china) -foreground red&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와 같이 하면 됩니다. 마찬가지로&amp;nbsp;값을&amp;nbsp;얻으려면&amp;nbsp;entry&amp;nbsp;cget&amp;nbsp;서브커맨드를&amp;nbsp;사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759126396177&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set label [.ta entry cget $ids(/china) -label]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 왼쪽에 표시된 부분의 설명이었습니다.&lt;br /&gt;&lt;br /&gt;오른쪽 부분을 만들려면, 먼저 column insert 서브커맨드로 왼쪽부터 차례로 컬럼을 추가합니다. end 뒤의 문자열은 각 열을 고유하게 식별할 컬럼 ID를 적당히 지정합니다. 이때&amp;nbsp;-text&amp;nbsp;옵션으로&amp;nbsp;헤더&amp;nbsp;문자열을&amp;nbsp;지정할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759126663857&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.ta column insert end &quot;emps&quot; -text 직원수
.ta column insert end &quot;equips&quot; -text 설비대수
.ta column insert end &quot;start_date&quot; -text 시작연월&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 각 아이템에 대해 -data 옵션으로 표시하고 싶은 데이터를 지정합니다. 그 데이터는 &quot;컬럼 ID&quot;와 &quot;값&quot;을 번갈아 나열한 리스트 형태입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759126697922&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.ta entry configure $ids(/korea/boondang) \
  -data {emps 45 equips 130 start_date 200010}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 각 아이템에 대해 반복하면 트리뷰가 완성됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;BLT 그래프의 다양한 기능&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;여러 막대그래프를 나란히 그리기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는&amp;nbsp; 인구 그래프로 아래의 이미지와 같이 동일한 X축, Y축에 대해 여러 개의 막대그래프를 그릴 수 있습니다. 주의해야 할 점은, BLT에서는 기본적으로 한 번에 4개(X축 2개, Y축 2개)까지 그릴 수 있는데, 좌표축이 다른 막대그래프를 여러 개 그리려고 하면 뒤쪽 막대가 앞쪽 막대를 가려서 제대로 보이지 않습니다. 이런 경우는 뒤에서 설명할 꺾은선그래프를 사용하는 것이 좋습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kVpkk/btsQVLXPTt6/oWMxpBkKD2wGAWIdj2Q7Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kVpkk/btsQVLXPTt6/oWMxpBkKD2wGAWIdj2Q7Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kVpkk/btsQVLXPTt6/oWMxpBkKD2wGAWIdj2Q7Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkVpkk%2FbtsQVLXPTt6%2FoWMxpBkKD2wGAWIdj2Q7Ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;482&quot; height=&quot;449&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1759127774902&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . &quot;5대 도시의 인구&quot;

barchart .bc \
 -background &quot;#808080&quot; -barwidth 1 -plotbackground &quot;#c0c0c0&quot; \
 -plotrelief sunken -plotborderwidth 2 \
 -title &quot;5대 도시의 인구&quot; -relief groove -bd 2 -barmode aligned

set x_dummy {1 2 3 4 5}
set Popu1992 {10446 3829 2371 2065 1185}
set Popu2025 {9210 3210 2296 2959 1439}

proc getPrefName {bc n args} {
    set prefName {dummy 서울 부산 대구 인천 광주}
    return [lindex $prefName $n]
}

.bc element create ELEM1992 -hide no \
  -xdata $x_dummy -ydata $Popu1992 -label &quot;1992년 조사&quot; \
  -fg &quot;#700040&quot; -bg white -relief sunken -stipple gray50 \
  -bindtags TagBarElems

.bc element create ELEM2025 -hide no \
  -xdata $x_dummy -ydata $Popu2025 -label &quot;2025년 조사&quot; \
  -fg &quot;#006000&quot; -bg white -relief sunken -stipple gray50 \
  -bindtags TagBarElems

.bc element bind TagBarElems &amp;lt;Button-1&amp;gt; {
    # invtransform은 윈도우 좌표를 좌표축의 좌표로 변환합니다.
    # &quot;invtransform&quot; 다음의 x, y 등은 좌표축의 이름입니다.
    set x [.bc axis invtransform x %x]
    set y [.bc axis invtransform y %y]
    tk_messageBox -message &quot;안녕하세요! $x $y&quot;
}

# 좌표축은 기본적으로 x,x2,y,y2의 4가지가 정의되어 있고, x와 y는 기본적으로
# -hide no, x2와 y2는 -hide yes입니다.
.bc axis configure x \
  -color white -command getPrefName -title 부현 -titlecolor #c0c0c0 \
  -showticks 1

.bc axis configure y \
  -color white -min 0 -max 12000 -hide no -showticks 1 \
  -title &quot;인구&quot; -titlefont {{굴림} 14 normal}

.bc legend configure -position right -relief groove -bd 2 \
  -font 7x14 -fg #000060
.bc grid configure -hide no -color &quot;#808080&quot; -dashes {1 4 1} \
  -mapx {} -mapy y

pack .bc -side top
pack [button .cmda -text 닫기 -command exit] -anc e&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막대그래프를 나란히 표시하려면, `barchart`의 `element create` 서브커맨드를 그 수만큼 실행하면 됩니다. 물론, 이 때 각 element의 `-xdata`는 동일하게 설정해야 합니다. 또한 여러 막대의 나열 방식을 `barchart` 위젯의 `-barmode` 옵션으로 지정할 수 있다는 것입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;infront: 뒤에 표시되는 아이템이 앞의 아이템 위치를 덮어써서 표시합니다.&lt;/li&gt;
&lt;li&gt;stacked: 막대그래프를 누적 표시합니다.&lt;/li&gt;
&lt;li&gt;aligned: 옆으로 나란히 표시합니다.&lt;/li&gt;
&lt;li&gt;overlap: 옆으로 나란히 표시하지만, 약간 앞의 아이템과 겹치게 표시합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서는 `aligned`를 사용하였으므로, 각 막대가 `element create`를 실행한 순서대로 왼쪽에서 오른쪽으로 나란히 정렬되어 있습니다. 참고로, 좀 더 멋을 내기 위해 막대그래프에 그림자를 추가하여 3D 느낌을 내거나 여러 효과를 주고 있는데, `-stipple` 옵션을 사용하면 속도가 느려지므로, 보통은 사용하지 않는 것이 좋습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;여러 개의 꺾은선그래프를 나란히 그리기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 야채 생산량 데이타로 서로 다른 Y축에 꺽은선 그래프를 여러개 그린 예 입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759195841495&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . &quot;BLT 샘플&quot;
graph .g -background &quot;#808080&quot; -plotbackground &quot;#c0c0c0&quot; \
 -plotrelief sunken -plotborderwidth 2 \
 -title &quot;야채 생산량&quot; -relief groove -bd 2

set x_dummy {1 2 3 4 5}
set CornData {4040 4563 6512 7328 6684 5879}
set PoData  { 340  328  457  813  489  507}

proc getYear {gc n args} {
    set y {dummy 1993 1994 1995 1996 1997 1998}
    return [lindex $y $n]
}

.g element create ELEM_AREA -hide no \
  -xdata $x_dummy -ydata $CornData -label &quot;옥수수(왼쪽)&quot; \
  -color white -dashes {1 5 1} -fill #600000 -pixels 4 \
  -linewidth 1 -outline #f00000 -outlinewidth 1 -symbol square \
  -bindtags TagElems -mapy y -mapx x

.g element create ELEM_POPU -hide no \
  -xdata $x_dummy -ydata $PoData -label &quot;고구마(오른쪽)&quot; \
  -color yellow -dashes {1 5 1} -fill #000060 -pixels 4 \
  -linewidth 1 -outline #0000f0 -outlinewidth 1 -symbol circle \
  -bindtags TagElems -mapy y2 -mapx x

.g element bind TagBarElems &amp;lt;Button-1&amp;gt; {
  tk_messageBox -message &quot;안녕하세요!&quot;
}

# 좌표축은 기본적으로 x, x2, y, y2의 4가지가 정의되어 있고
# x와 y는 기본적으로 -hide no, x2와 y2는 -hide yes입니다.
.g axis configure x \
  -color white -command getYear -title 연도 -titlecolor #c0c0c0 \
  -showticks 1

.g axis configure y \
  -color white -min 0 -max 10000 -hide no -showticks 1

.g axis configure y2 \
  -color white -min 0 -max 1000 -hide no -showticks 1

.g legend configure -position right -relief groove -bd 2 \
  -font 7x14 -fg #000060

.g grid configure -hide no -color &quot;#808080&quot; -dashes {1 4 1} \
  -mapx &quot;&quot; -mapy y
pack .g -side top -padx 4 -pady 4
pack [ttk::button .cmda -text 종료 -command exit] -anc e -padx 8
. configure -bg #206020&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HqLUL/btsQWxrH5hZ/FJKW3j4Bef64KGNtkAZWcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HqLUL/btsQWxrH5hZ/FJKW3j4Bef64KGNtkAZWcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HqLUL/btsQWxrH5hZ/FJKW3j4Bef64KGNtkAZWcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHqLUL%2FbtsQWxrH5hZ%2FFJKW3j4Bef64KGNtkAZWcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;449&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막대그래프 때처럼 element create를 각각 다른 데이터에 대해 여러 번 실행하면, 같은 X축, Y축 위에 여러 개의 꺾은선그래프를 그릴 수 있습니다. 하지만 이것만으로는 막대그래프 예제와 거의 다르지 않기 때문에, 여기서는 서로 다른 Y축 위에 각각 꺾은선그래프를 그려 보았습니다.&lt;br /&gt;&lt;br /&gt;이를 위해서는 먼저, graph 위젯의 axis configure 서브커맨드로 두 번째 Y좌표축인 &quot;y2&quot;축을 설정해줘야 합니다. 특히 -hide no를 반드시 해야 합니다. Y2축은 기본값이 &quot;숨김&quot;이기 때문입니다. 따로&amp;nbsp;조작하지&amp;nbsp;않으면,&amp;nbsp;주&amp;nbsp;Y축(y)은&amp;nbsp;왼쪽에,&amp;nbsp;y2축은&amp;nbsp;오른쪽에&amp;nbsp;나타납니다. &lt;br /&gt;&lt;br /&gt;다음으로 element create로 각 꺾은선을 만들 때, -mapy 옵션으로 해당 꺾은선이 참조할 Y좌표축을 지정합니다. 여기서는 옥수수를 왼쪽 &quot;y&quot;축에, 고구마를 오른쪽 &quot;y2&quot;축에 대응시켰습니다. 아래 꺽은선그래프의 그리기 옵션에 대해 정리해두겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-color : 선 색상 (기본값: 검정)&lt;/li&gt;
&lt;li&gt;-dashes : 선을 점선(파선)으로 할 때 패턴 (기본값: {} &amp;rarr; 실선)&lt;/li&gt;
&lt;li&gt;-linewidth : 선 두께 (기본값: 0 &amp;rarr; 선 없이 심볼만 표시)&lt;/li&gt;
&lt;li&gt;-fill : 심볼의 채우기 색 (기본값: {} &amp;rarr; 채우지 않음)&lt;/li&gt;
&lt;li&gt;-outline : 심볼 테두리 색 (기본값: {} &amp;rarr; 테두리 없음)&lt;/li&gt;
&lt;li&gt;-outlinewidth : 테두리 두께 (기본값: 1)&lt;/li&gt;
&lt;li&gt;-symbol : 심볼 모양 (square, circle, diamond, plus, cross, splus, scross, triangle, {}=심볼 없음 중 선택)&lt;/li&gt;
&lt;li&gt;-pixels&amp;nbsp;:&amp;nbsp;심볼&amp;nbsp;크기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본값으로는 심볼이 보이지 않으니 주의 하세요. 그리고 기본 심볼 크기가 너무 크니, 반드시 -pixels 옵션으로 크기를 조정하면 됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;꺾은선그래프와 막대그래프를 함께 표시하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개의 꺾은선그래프를 표시하는 방법을 응용하면, 꺾은선그래프와 막대그래프를 동시에 그리는 것도 아주 쉽습니다. 기본적으로&amp;nbsp;graph&amp;nbsp;위젯에서,&amp;nbsp;element&amp;nbsp;create&amp;nbsp;대신&amp;nbsp;bar&amp;nbsp;create를&amp;nbsp;쓰면&amp;nbsp;됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1759196393623&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require BLT
namespace import blt::*
namespace import -force blt::tile::*

wm title . &quot;BLT 샘플&quot;
graph .g -background &quot;#808080&quot; -plotbackground &quot;#c0c0c0&quot; \
 -plotrelief sunken -plotborderwidth 2 \
 -title &quot;야채 생산량&quot; -relief groove -bd 2

set x_dummy {1 2 3 4 5}
set CornData {4040 4563 6512 7328 6684 5879}
set PoData  { 340  328  457  813  489  507}

proc getYear {gc n args} {
    set y {dummy 1993 1994 1995 1996 1997 1998}
    return [lindex $y $n]
}

.g element create ELEM_AREA -hide no \
  -xdata $x_dummy -ydata $CornData -label &quot;옥수수(왼쪽)&quot; \
  -color white -dashes {1 5 1} -fill #600000 -pixels 4 \
  -linewidth 1 -outline #f00000 -outlinewidth 1 -symbol square \
  -bindtags TagElems -mapy y -mapx x

.g bar create ELEM_POPU -hide no \
  -xdata $x_dummy -ydata $PoData -label &quot;고구마(오른쪽)&quot; \
  -fg #000060 -bg white -relief raised -bd 2 \
  -bindtags TagElems -mapy y2 -mapx x

.g element bind TagBarElems &amp;lt;Button-1&amp;gt; {
  tk_messageBox -message &quot;안녕하세요!&quot;
}

.g axis configure x \
  -color white -command getYear -title 연도 -titlecolor #c0c0c0 \
  -showticks 1

.g axis configure y \
  -color white -min 0 -max 10000 -hide no -showticks 1

.g axis configure y2 \
  -color white -min 0 -max 1000 -hide no -showticks 1

.g legend configure -position right -relief groove -bd 2 \
  -font 7x14 -fg #000060

.g grid configure -hide no -color &quot;#808080&quot; -dashes {1 4 1} \
  -mapx &quot;&quot; -mapy y
pack .g -side top -padx 4 -pady 4
pack [ttk::button .cmda -text 종료 -command exit] -anc e -padx 8
. configure -bg #206020&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sovKi/btsQWSJe72y/ArxhkTegktIvlKv9ixPjE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sovKi/btsQWSJe72y/ArxhkTegktIvlKv9ixPjE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sovKi/btsQWSJe72y/ArxhkTegktIvlKv9ixPjE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsovKi%2FbtsQWSJe72y%2FArxhkTegktIvlKv9ixPjE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;449&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;똑똑하게 범례(legend)도 자동으로 변경됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;원형그래프&amp;nbsp;(piechart)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아쉽게도 BLT에는 원형그래프를 제공하지 않습니다. 대신 &lt;a href=&quot;https://tcltk.co.kr/327&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;tkpiechart&lt;/a&gt;를 사용하시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;239&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7xIAf/btsQVUOkjYd/hPyMvCB4kWgQL7Kd8qKOPK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7xIAf/btsQVUOkjYd/hPyMvCB4kWgQL7Kd8qKOPK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7xIAf/btsQVUOkjYd/hPyMvCB4kWgQL7Kd8qKOPK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b7xIAf/btsQVUOkjYd/hPyMvCB4kWgQL7Kd8qKOPK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;239&quot; height=&quot;143&quot; data-origin-width=&quot;239&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/pages/%EA%B7%B8%EB%9E%98%ED%94%84-%EC%9C%84%EC%A0%AF%EC%9D%98-%EC%B5%9C%EA%B0%95%EC%9E%90-BLT</guid>
      <pubDate>Wed, 24 Sep 2025 10:18:19 +0900</pubDate>
    </item>
    <item>
      <title>Blend2d 1.6</title>
      <link>https://ihmin.tistory.com/697</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://sourceforge.net/projects/irrational-numbers/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://sourceforge.net/projects/irrational-numbers/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TclBlend2d는 Blend2d 그래픽 엔진을 다루기 위한 Tcl 패키지입니다. Blend2d는 오픈 소스이자 고품질, 고성능의 벡터 그래픽 엔진입니다. TclBlend2d는 Windows와 Linux용 Blend2d 라이브러리를 포함한 멀티플랫폼 바이너리 패키지입니다. MacOS 지원도 계획되어 있습니다. TclBlend2d로 생성한 이미지는 BMP 파일로 저장하거나 tk-photo 이미지로 저장할 수 있습니다. TclBlend2d는 &quot;blend2d&quot;라는 새로운 유형의 tk-image도 제공합니다. 이 이미지는 tk-photo 이미지처럼 위젯에 임베드하여 사용할 수 있습니다. &quot;blend2d&quot; tk-image에 그림을 그리고, 이 이미지가 연결된 위젯에서 바로 변경된 내용을 확인할 수 있습니다. TclBlend2d는&amp;nbsp;Blend2d&amp;nbsp;C++&amp;nbsp;API와&amp;nbsp;거의&amp;nbsp;동일하게&amp;nbsp;동작하지만,&amp;nbsp;Tcl&amp;nbsp;방식이&amp;nbsp;더&amp;nbsp;적합한&amp;nbsp;경우에는&amp;nbsp;예외적으로&amp;nbsp;Tcl&amp;nbsp;스타일을&amp;nbsp;따릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TclBlend2d is a Tcl package for working with the Blend2d&amp;nbsp;&amp;nbsp;graphics engine. Blend2d is an open source, high quality, high-performance vector graphics engine. TclBlend2d is a multiplatform binary package including Blend2d library for Windows and Linux; MacOS support is planned. Images created with TclBlend2d can be saved as BMP files, or exchanged with the tk-photo images. TclBlend2s provides also a new type of tk-image (named &quot;blend2d&quot;) you can embed in your widgets much like a tk-photo image. You can draw on a &quot;blend2d&quot; tk-image and instantly see the changes in the widgets that have this image attached. TclBlend2d closely matches the Blend2d C++ API with the exception of cases where a more Tcl-ish way is more appropriate.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ShLjq/btsQIY5B1UJ/kXaUWgjIMH2em7KQO2s3H1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ShLjq/btsQIY5B1UJ/kXaUWgjIMH2em7KQO2s3H1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ShLjq/btsQIY5B1UJ/kXaUWgjIMH2em7KQO2s3H1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FShLjq%2FbtsQIY5B1UJ%2FkXaUWgjIMH2em7KQO2s3H1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;503&quot; height=&quot;385&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;846&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sG6O0/btsQH9TRvKX/Bz0z8QhfxEsyOCRrKZhII0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sG6O0/btsQH9TRvKX/Bz0z8QhfxEsyOCRrKZhII0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sG6O0/btsQH9TRvKX/Bz0z8QhfxEsyOCRrKZhII0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsG6O0%2FbtsQH9TRvKX%2FBz0z8QhfxEsyOCRrKZhII0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;502&quot; height=&quot;530&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;846&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/k6VsG/dJMb9Om4afS/YAjjyLC7e48vLSk4UpWnu0/blend2d-1.6.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;blend2d-1.6.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;8.30MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/697</guid>
      <comments>https://ihmin.tistory.com/697#entry697comment</comments>
      <pubDate>Mon, 22 Sep 2025 21:59:07 +0900</pubDate>
    </item>
    <item>
      <title>트리 스타일의 표시 위젯 TkTreeCtrl</title>
      <link>https://ihmin.tistory.com/pages/%ED%8A%B8%EB%A6%AC-%EC%8A%A4%ED%83%80%EC%9D%BC%EC%9D%98-%ED%91%9C%EC%8B%9C-%EC%9C%84%EC%A0%AF-TkTreeCtrl</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;TkTreeCtrl은 ttk::treeview와 마찬가지로 계층적인 트리 표시가 가능한 리스트 박스 위젯입니다. 여러 데이터 항목을 여러 열에 표시할 수 있으며, 약간의 코딩이 필요하지만 셀의 인라인 편집도 가능합니다. 특징은 매우 많은 설정 항목을 가지고 있어 다양한 표시를 구현할 수 있다는 점입니다. 참고 매뉴얼은 [&lt;a href=&quot;https://tktreectrl.sourceforge.net/treectrl.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기&lt;/a&gt;] 에서 볼 수 있습니다. 여기 나열된 위젯 명령만 보더라도 상당한 기능을 엿볼 수 있습니다. 최신 버전은 2.2.10입니다. Windows에서는 ActiveTcl 배포판에 포함되어 바로 사용할 수 있지만, 위의 사이트에서 별도로 소스 및 바이너리 배포본을 다운로드할 수도 있습니다. 그 중 demos 디렉토리에는 다양한 데모가 포함되어 있습니다. &lt;br /&gt;&lt;br /&gt;이 강좌에서는 트리 표시 예시 말고, 세로와 가로 2차원 표 형식의 표시, 편집 화면 샘플을 만들어 올려봅니다. &lt;br /&gt;&lt;br /&gt;아래의 탭으로 구분 지어진 인구수를 표시한 텍스트 샘플을 만듭니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758254095465&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1	서울특별시	수도권 	광역단체 	9,407,540
2	부산광역시	영남권 	광역단체 	3,320,276
3	인천광역시	수도권 	광역단체 	2,964,820
4	대구광역시	영남권 	광역단체 	2,365,619
5	대전광역시	호서권 	광역단체 	1,446,749
6	광주광역시	호남권 	광역단체 	1,432,049
8	울산광역시	영남권 	광역단체 	1,111,371&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl 프로그램은 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1758253972313&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require treectrl

# 탭으로 구분된 텍스트 파일을 읽어서
# 내용을 행, 열 2차원 리스트에 저장하여 반환합니다.
proc readDataFile dataVar {
    upvar $dataVar data
	set fd [open &quot;./data.txt&quot; r]
	set rows [split [read $fd] \n]
    set data {}
    foreach rowStr $rows {
        set rowArr [split $rowStr &quot;\t&quot;]
        if {[llength $rowArr] != 0} { lappend data $rowArr }
    }
}

# treectrl 위젯 생성
set f [frame .f]
set t [treectrl2 $f.t -font {Helvetica 12 normal} -width 400 -height 200 \
  -xscrollcommand &quot;$f.x set&quot; -yscrollcommand &quot;$f.y set&quot; ]
scrollbar $f.x -ori h -com &quot;$t xview&quot;
scrollbar $f.y -ori v -com &quot;$t yview&quot;
grid $t $f.y -sti news
grid    $f.x -sti news
grid rowconfig $f 0 -weight 1
grid columnconfig $f 0 -weight 1
pack $f

# 열 생성 및 헤더 행 정의
set x 0
foreach e [list 순위 행정구역 행정구분 인구수] {
    $t column create -text $e -expand yes -button no \
      -itembackground {#ffdddd #ddddff}
    if {$x == 0 || $x == 3} {
        $t column configure $x -itemjustify right
    }
    incr x
}

# 데이터 파일 읽기
readDataFile data

# Element 생성
$t element create eText text -fill [list #800000 { selected focus }]

# Style 생성
$t style create s1
$t style elements s1 eText
$t style layout s1 eText -padx {4 6} -expand ns -iexpand ns -sticky s

# 각 데이터 행(item) 생성
foreach rowData $data {
    set rowId [$t item create]
    set col 0
    foreach cell $rowData {
        $t item style set $rowId $col s1
        $t item text $rowId $col [lindex $rowData $col]
        incr col
    }
    $t item lastchild root $rowId
}

bind . &amp;lt;Control-q&amp;gt; exit&lt;/code&gt;&lt;/pre&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/pages/%ED%8A%B8%EB%A6%AC-%EC%8A%A4%ED%83%80%EC%9D%BC%EC%9D%98-%ED%91%9C%EC%8B%9C-%EC%9C%84%EC%A0%AF-TkTreeCtrl</guid>
      <pubDate>Fri, 19 Sep 2025 13:10:20 +0900</pubDate>
    </item>
    <item>
      <title>도스 폰트</title>
      <link>https://ihmin.tistory.com/695</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;도스시절의 16x16 사이즈 비트맵 폰트 스타일을 적용해보고자 한다면..&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;네오 둥근모&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/neodgm/neodgm-pro/releases&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/neodgm/neodgm-pro/releases&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vzx9M/btsQDVavtSM/Ff8gjE2ZKhbpvE4W80LZnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vzx9M/btsQDVavtSM/Ff8gjE2ZKhbpvE4W80LZnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vzx9M/btsQDVavtSM/Ff8gjE2ZKhbpvE4W80LZnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvzx9M%2FbtsQDVavtSM%2FFf8gjE2ZKhbpvE4W80LZnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;603&quot; height=&quot;334&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/0W3Pr/dJMb9OAAH3b/urteg5aWcJV3jra2kMfYq0/NeoDunggeunmoPro-Regular.woff?attach=1&amp;amp;knm=tfile.woff&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;NeoDunggeunmoPro-Regular.woff&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.10MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/le6l9/dJMb9OAAH3v/2nUbW8Odpzb0IGxIaYQHJk/NeoDunggeunmoPro-Regular.ttf?attach=1&amp;amp;knm=tfile.ttf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;NeoDunggeunmoPro-Regular.ttf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.64MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/6RCVV/dJMb9OAAH3w/TzLNReuRmKb9CkRgvgYghK/NeoDunggeunmoPro-Regular.woff2?attach=1&amp;amp;knm=tfile.woff2&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;NeoDunggeunmoPro-Regular.woff2&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.04MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HBIOS-SYS&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hbios.quiple.dev&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hbios.quiple.dev/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://noonnu.cc/font_page/960&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://noonnu.cc/font_page/960&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GBkKB/btsQDVBEpAt/EK4gY86BIweJ8rXZYc2pS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GBkKB/btsQDVBEpAt/EK4gY86BIweJ8rXZYc2pS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GBkKB/btsQDVBEpAt/EK4gY86BIweJ8rXZYc2pS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGBkKB%2FbtsQDVBEpAt%2FEK4gY86BIweJ8rXZYc2pS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;586&quot; height=&quot;408&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/V4QaP/dJMb8XYACG5/kiTuc6tNEjuttUIOsfmlz0/HBIOS-SYS.ttf?attach=1&amp;amp;knm=tfile.ttf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;HBIOS-SYS.ttf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;5.41MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/WRlcL/dJMb81mnUY9/0UE1M4kYkopfsDusCdNnHk/HBIOS-SYS.woff?attach=1&amp;amp;knm=tfile.woff&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;HBIOS-SYS.woff&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.89MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/k3m4E/dJMb8XYACG9/CJZjqOgOZk2Nm5rXiOfvY1/HBIOS-SYS.woff2?attach=1&amp;amp;knm=tfile.woff2&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;HBIOS-SYS.woff2&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.50MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도스 유명 폰트들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/hurss/fonts&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/hurss/fonts&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://noonnu.cc/index?search=leedheo&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://noonnu.cc/index?search=leedheo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;596&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N7A3I/btsQEOPbkoO/jVfXOz1k2dQADGkYGg8JdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N7A3I/btsQEOPbkoO/jVfXOz1k2dQADGkYGg8JdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N7A3I/btsQEOPbkoO/jVfXOz1k2dQADGkYGg8JdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN7A3I%2FbtsQEOPbkoO%2FjVfXOz1k2dQADGkYGg8JdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;596&quot; height=&quot;530&quot; data-origin-width=&quot;596&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/PvvJH/dJMb9OghXZZ/H3SGMSXMbvkpsH2nYxcGQK/fonts-master.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;fonts-master.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;15.92MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>Font</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/695</guid>
      <comments>https://ihmin.tistory.com/695#entry695comment</comments>
      <pubDate>Fri, 19 Sep 2025 09:56:32 +0900</pubDate>
    </item>
    <item>
      <title>thtmlview</title>
      <link>https://ihmin.tistory.com/694</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://github.com/mittelmark/thtmlview&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/mittelmark/thtmlview&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thtmlview&amp;nbsp;패키지는&amp;nbsp;기본적인&amp;nbsp;HTML&amp;nbsp;및&amp;nbsp;Markdown&amp;nbsp;파일을&amp;nbsp;표시할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;순수&amp;nbsp;Tcl/Tk&amp;nbsp;위젯을&amp;nbsp;제공합니다.&amp;nbsp;사용하려면&amp;nbsp;Tcllib&amp;nbsp;패키지의&amp;nbsp;snit가&amp;nbsp;설치되어&amp;nbsp;있어야&amp;nbsp;합니다.&amp;nbsp;Markdown&amp;nbsp;파일을&amp;nbsp;표시하려면&amp;nbsp;Tcllib의&amp;nbsp;Markdown&amp;nbsp;패키지도&amp;nbsp;추가로&amp;nbsp;설치해야&amp;nbsp;합니다.&amp;nbsp;JPEG&amp;nbsp;이미지를&amp;nbsp;지원하려면&amp;nbsp;TkImg&amp;nbsp;패키지가&amp;nbsp;필요합니다. &lt;br /&gt;&lt;br /&gt;이&amp;nbsp;위젯은&amp;nbsp;웹&amp;nbsp;브라우저가&amp;nbsp;아닙니다.&amp;nbsp;http(s)&amp;nbsp;주소를&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없으며,&amp;nbsp;이미지와&amp;nbsp;링크에는&amp;nbsp;반드시&amp;nbsp;상대&amp;nbsp;파일명을&amp;nbsp;사용해야&amp;nbsp;합니다.&amp;nbsp;또한&amp;nbsp;위젯은&amp;nbsp;HTML&amp;nbsp;페이지에&amp;nbsp;직접&amp;nbsp;임베드된&amp;nbsp;base64&amp;nbsp;인코딩&amp;nbsp;이미지도&amp;nbsp;지원합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;thtmlview는 해당 패키지의 개발자가 만든 다른 위젯인 shtmlview를 포크한 것입니다. shtmlview는&amp;nbsp;&lt;a href=&quot;https://github.com/tcltk/tklib&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/tcltk/tklib&lt;/a&gt;에서&amp;nbsp;찾으실&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;thtmlview의&amp;nbsp;변경사항을&amp;nbsp;shtmlview에&amp;nbsp;적용하고&amp;nbsp;싶었지만,&amp;nbsp;저는&amp;nbsp;fossil을&amp;nbsp;사용하지&amp;nbsp;않으므로&amp;nbsp;일반적인&amp;nbsp;포크&amp;nbsp;및&amp;nbsp;병합&amp;nbsp;방식이&amp;nbsp;작동하지&amp;nbsp;않았습니다.&amp;nbsp;그래서&amp;nbsp;tcllib&amp;nbsp;위젯과&amp;nbsp;구분하기&amp;nbsp;위해&amp;nbsp;제&amp;nbsp;위젯의&amp;nbsp;이름을&amp;nbsp;shtmlview에서&amp;nbsp;thtmlview로&amp;nbsp;변경하기로&amp;nbsp;했습니다.&amp;nbsp;이런&amp;nbsp;포크를&amp;nbsp;하게&amp;nbsp;되어&amp;nbsp;죄송하지만,&amp;nbsp;저는&amp;nbsp;제&amp;nbsp;소프트웨어에서&amp;nbsp;위젯을&amp;nbsp;직접&amp;nbsp;사용하고&amp;nbsp;확장해야&amp;nbsp;했고,&amp;nbsp;그것이&amp;nbsp;tklib에서&amp;nbsp;지원하는&amp;nbsp;방식과는&amp;nbsp;다를&amp;nbsp;수&amp;nbsp;있기&amp;nbsp;때문입니다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;711&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ryNkz/btsQCrGCuZk/JLfNvZMAZigNk4FKgF57G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ryNkz/btsQCrGCuZk/JLfNvZMAZigNk4FKgF57G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ryNkz/btsQCrGCuZk/JLfNvZMAZigNk4FKgF57G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FryNkz%2FbtsQCrGCuZk%2FJLfNvZMAZigNk4FKgF57G1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1138&quot; height=&quot;711&quot; data-origin-width=&quot;1138&quot; data-origin-height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/RsKP3/dJMb8Z9Whrx/3YpqKxosvsMIvFT2OOmCFK/thtmlview-main.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;thtmlview-main.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.16MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/694</guid>
      <comments>https://ihmin.tistory.com/694#entry694comment</comments>
      <pubDate>Thu, 18 Sep 2025 10:08:17 +0900</pubDate>
    </item>
    <item>
      <title>네이버 카페 백업을 도와 드립니다.</title>
      <link>https://ihmin.tistory.com/notice/693</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;현재 운영 중인 네이버 카페가 있습니다. 카페 목적상 사진과 글 그리고 첨부 파일들이 많은 편입니다. 그래서 따로 카페의 백업을 위해 모든 게시글을 이미지, 첨부파일 그리고 댓글까지 포함하는 백업 프로그램을 개발해서 사용 중입니다. (현재까지 9만여개의 게시글을 백업하였습니다) 간혹 백업 중 에러가 나긴 하지만 99.9% 정도는 백업이 되며, 다른 싸이트에 이동이 용이하도록 가공이 되어 백업이 되고 있습니다. 혹시 운영중이신 네이버 카페의 백업이 필요하신 분은 방명록에 남겨주세요. 단 일정의 백업비용은 받고 있습니다. 감사합니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;지금까지 4곳의 카페 백업이 완료가 되었습니다.&lt;br /&gt;- 2025..... 1-3번째 백업 완료&lt;br /&gt;- 2025/02/20 4번째 백업 완료&lt;br /&gt;- 2025/03/26 5번째 백업 완료&lt;br /&gt;-&amp;nbsp;2025/04/08&amp;nbsp;6번째&amp;nbsp;백업&amp;nbsp;완료&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/notice/693</guid>
      <pubDate>Tue, 9 Sep 2025 14:28:42 +0900</pubDate>
    </item>
    <item>
      <title>요소 절점 순서 (element node odering)</title>
      <link>https://ihmin.tistory.com/692</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;출처:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering&quot;&gt;https://gmsh.info/doc/texinfo/gmsh.html#Node-ordering&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 요소 절점 순서...&lt;/p&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Line:                  Line3:           Line4:

      v
      ^
      |
      |
0-----+-----1 --&amp;gt; u    0----2----1      0---2---3---1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Triangle:               Triangle6:          Triangle9/10:

v
^
|
2                       2                    2
|`\                     |`\                  | \
|  `\                   |  `\                7   6
|    `\                 5    `4              |     \
|      `\               |      `\            8  (9)  5
|        `\             |        `\          |         \
0----------1--&amp;gt; u       0-----3----1         0---3---4---1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Triangle12/15:

 v
 ^
 |
 2
 | \
 9   8
 |     \
10 (14)  7
 |         \
11 (12) (13) 6
 |             \
 0---3---4---5---1--&amp;gt; u&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Quadrangle:            Quadrangle8:            Quadrangle9:

      v
      ^
      |
3-----------2          3-----6-----2           3-----6-----2
|     |     |          |           |           |           |
|     |     |          |           |           |           |
|     +---- | --&amp;gt; u    7           5           7     8     5
|           |          |           |           |           |
|           |          |           |           |           |
0-----------1          0-----4-----1           0-----4-----1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Tetrahedron:                          Tetrahedron10:

                   v
                 .
               ,/
              /
           2                                     2
         ,/|`\                                 ,/|`\
       ,/  |  `\                             ,/  |  `\
     ,/    '.   `\                         ,6    '.   `5
   ,/       |     `\                     ,/       8     `\
 ,/         |       `\                 ,/         |       `\
0-----------'.--------1 --&amp;gt; u         0--------4--'.--------1
 `\.         |      ,/                 `\.         |      ,/
    `\.      |    ,/                      `\.      |    ,9
       `\.   '. ,/                           `7.   '. ,/
          `\. |/                                `\. |/
             `3                                    `3
                `\.
                   ` w&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Hexahedron:             Hexahedron20:          Hexahedron27:

       v
3----------2            3----13----2           3----13----2
|\     ^   |\           |\         |\          |\         |\
| \    |   | \          | 15       | 14        |15    24  | 14
|  \   |   |  \         9  \       11 \        9  \ 20    11 \
|   7------+---6        |   7----19+---6       |   7----19+---6
|   |  +-- |-- | -&amp;gt; u   |   |      |   |       |22 |  26  | 23|
0---+---\--1   |        0---+-8----1   |       0---+-8----1   |
 \  |    \  \  |         \  17      \  18       \ 17    25 \  18
  \ |     \  \ |         10 |        12|        10 |  21    12|
   \|      w  \|           \|         \|          \|         \|
    4----------5            4----16----5           4----16----5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Prism:                      Prism15:               Prism18:

           w
           ^
           |
           3                       3                      3
         ,/|`\                   ,/|`\                  ,/|`\
       ,/  |  `\               12  |  13              12  |  13
     ,/    |    `\           ,/    |    `\          ,/    |    `\
    4------+------5         4------14-----5        4------14-----5
    |      |      |         |      8      |        |      8      |
    |    ,/|`\    |         |      |      |        |    ,/|`\    |
    |  ,/  |  `\  |         |      |      |        |  15  |  16  |
    |,/    |    `\|         |      |      |        |,/    |    `\|
   ,|      |      |\        10     |      11       10-----17-----11
 ,/ |      0      | `\      |      0      |        |      0      |
u   |    ,/ `\    |    v    |    ,/ `\    |        |    ,/ `\    |
    |  ,/     `\  |         |  ,6     `7  |        |  ,6     `7  |
    |,/         `\|         |,/         `\|        |,/         `\|
    1-------------2         1------9------2        1------9------2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;bash&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;Pyramid:                     Pyramid13:

               4                            4
             ,/|\                         ,/|\
           ,/ .'|\                      ,/ .'|\
         ,/   | | \                   ,/   | | \
       ,/    .' | `.                ,/    .' | `.
     ,/      |  '.  \             ,7      |  12  \
   ,/       .' w |   \          ,/       .'   |   \
 ,/         |  ^ |    \       ,/         9    |    11
0----------.'--|-3    `.     0--------6-.'----3    `.
 `\        |   |  `\    \      `\        |      `\    \
   `\     .'   +----`\ - \ -&amp;gt; v  `5     .'        10   \
     `\   |    `\     `\  \        `\   |           `\  \
       `\.'      `\     `\`          `\.'             `\`
          1----------------2            1--------8-------2
                    `\
                       u&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #252525; text-align: start;&quot;&gt;
&lt;pre class=&quot;tex&quot; style=&quot;background-color: #f3f7ff; color: #000000;&quot;&gt;&lt;code&gt;Pyramid14:

               4
             ,/|\
           ,/ .'|\
         ,/   | | \
       ,/    .' | `.
     ,7      |  12  \
   ,/       .'   |   \
 ,/         9    |    11
0--------6-.'----3    `.
  `\        |      `\    \
    `5     .' 13     10   \
      `\   |           `\  \
        `\.'             `\`
           1--------8-------2
                    `\
                       u&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/692</guid>
      <comments>https://ihmin.tistory.com/692#entry692comment</comments>
      <pubDate>Mon, 8 Sep 2025 23:53:03 +0900</pubDate>
    </item>
    <item>
      <title>spinbox 강좌가 등록 되었습니다.</title>
      <link>https://ihmin.tistory.com/notice/691</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Tk의 위젯중 spinbox 에 대한 강좌가 등록되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tcltk.co.kr/pages/Tk%EC%9D%98-%EC%8A%A4%ED%95%80%EB%B0%95%EC%8A%A4-spinbox&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tk의&amp;nbsp;스핀박스&amp;nbsp;(spinbox)&lt;/a&gt;&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/notice/691</guid>
      <pubDate>Mon, 8 Sep 2025 21:45:34 +0900</pubDate>
    </item>
    <item>
      <title>Tk의 스핀박스 (spinbox)</title>
      <link>https://ihmin.tistory.com/pages/Tk%EC%9D%98-%EC%8A%A4%ED%95%80%EB%B0%95%EC%8A%A4-spinbox</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;스핀박스(spinbox)는 엔트리(entry) 위젯을 확장한 위젯입니다. 스핀박스는 엔트리의 오른쪽에 위/아래 버튼이 붙어 있어서, 엔트리에서 값을 직접 입력할 뿐만 아니라 위아래 버튼을 눌러 값을 선택할 수도 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;spinbox 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스핀박스는 spinbox 커맨드로 생성합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;spinbox 위젯명 옵션&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 옵션은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-from n -to m -increment i&lt;br /&gt;선택할 수 있는 숫자 범위를 n에서 m까지로 설정합니다. 버튼을 눌렀을 때의 증가값은 i입니다. i가 부동소수점일 경우, 표시도 부동소수점이 됩니다.&lt;/li&gt;
&lt;li&gt;-format 서식 문자열&amp;nbsp;&lt;br /&gt;선택하는 숫자가 부동소수점일 경우, 표시 방법을 서식 문자열로 지정합니다. 서식은 Tcl의 커맨드 format의 %f와 같습니다.&lt;/li&gt;
&lt;li&gt;-value 리스트&amp;nbsp;&amp;nbsp; &lt;br /&gt;선택할 항목을 리스트로 설정합니다.&lt;/li&gt;
&lt;li&gt;-state 상태&amp;nbsp;&amp;nbsp; &lt;br /&gt;스핀박스의&amp;nbsp;상태(normal,&amp;nbsp;readonly,&amp;nbsp;disabled)를&amp;nbsp;설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자는 옵션 -from n -to m -increment i로 간단하게 설정할 수 있습니다. 숫자가 부동소수점일 경우, 옵션 -format으로 표시 방법을 설정할 수 있습니다. 숫자가 아닌 경우에는 옵션 -value를 사용합니다. 항목을 리스트에 담아 -value에 설정합니다. -state를 readonly로 하면 엔트리에서의 입력이 금지되고 버튼만으로 값을 선택하게 됩니다. &lt;br /&gt;&lt;br /&gt;그럼&amp;nbsp;간단한&amp;nbsp;사용&amp;nbsp;예를&amp;nbsp;보여드리겠습니다.&amp;nbsp;다음&amp;nbsp;리스트를&amp;nbsp;보세요.&lt;/p&gt;
&lt;pre id=&quot;code_1757306547931&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spinbox .s1 -from 1 -to 10 -increment 1 -width 10  
spinbox .s2 -from 1 -to 5 -increment 0.5 -width 10 -format %05.2f  
spinbox .s3 -value {apple banana cherry grape orange} -width 10 -state readonly  

pack .s1 .s2 .s3 -padx 5 -pady 5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스핀박스를 3개 만듭니다. .s1은 1에서 10까지의 숫자로, -increment는 1입니다. .s2는 1에서 5까지의 숫자지만, -increment가 0.5이므로 부동소수점으로 표시됩니다. -format의 지정이 %05.2f이므로 표시는 01.50과 같이 됩니다. .s3은 apple, banana, cherry, grape, orange 중에서 선택합니다. -state에 readonly를 지정했으므로 엔트리로 입력할 수 없습니다. &lt;br /&gt;&lt;br /&gt;아래는 실행 결과입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 84.7638%; height: 113px;&quot; border=&quot;0&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 103px;&quot;&gt;
&lt;td style=&quot;width: 25.6776%; text-align: center; height: 103px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;122&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tG6vK/btsQns0zSH7/EZZCPEZfx4CNgXhi6VxOZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tG6vK/btsQns0zSH7/EZZCPEZfx4CNgXhi6VxOZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tG6vK/btsQns0zSH7/EZZCPEZfx4CNgXhi6VxOZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtG6vK%2FbtsQns0zSH7%2FEZZCPEZfx4CNgXhi6VxOZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;122&quot; height=&quot;119&quot; data-origin-width=&quot;122&quot; data-origin-height=&quot;119&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 30.8119%; text-align: center; height: 103px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;122&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eaZwLE/btsQqHIjb2w/359biCbDwdgQPvL9t4KTNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eaZwLE/btsQqHIjb2w/359biCbDwdgQPvL9t4KTNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eaZwLE/btsQqHIjb2w/359biCbDwdgQPvL9t4KTNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeaZwLE%2FbtsQqHIjb2w%2F359biCbDwdgQPvL9t4KTNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;122&quot; height=&quot;119&quot; data-origin-width=&quot;122&quot; data-origin-height=&quot;119&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.7908%; text-align: center; height: 103px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;122&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IETJU/btsQpySEFNO/q6kTxgCXW379SKQDo9Kjx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IETJU/btsQpySEFNO/q6kTxgCXW379SKQDo9Kjx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IETJU/btsQpySEFNO/q6kTxgCXW379SKQDo9Kjx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIETJU%2FbtsQpySEFNO%2Fq6kTxgCXW379SKQDo9Kjx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;122&quot; height=&quot;119&quot; data-origin-width=&quot;122&quot; data-origin-height=&quot;119&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 25.6776%; text-align: center; height: 10px;&quot;&gt;실행 직후의 상태&lt;/td&gt;
&lt;td style=&quot;width: 30.8119%; text-align: center; height: 10px;&quot;&gt;업 버튼을 한 번 누른 상태&lt;/td&gt;
&lt;td style=&quot;width: 33.7908%; text-align: center; height: 10px;&quot;&gt;업 버튼을 두 번 누른 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;입력 데이터 확인&amp;nbsp;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔트리 위젯에는 validation이라는 입력 데이터를 확인하는 기능이 있습니다. 스핀박스에서도 validation을 사용할 수 있습니다. validation 설정은 옵션 -validate와 -validatecommand(-vcmd)로 합니다. 옵션 -validate는 입력 데이터를 확인하는 타이밍을 지정합니다. 타이밍 종류는 다음과 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 62.3256%; height: 147px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 16.5698%; height: 21px; text-align: center;&quot;&gt;옵션&lt;/td&gt;
&lt;td style=&quot;width: 45.7558%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;-validate의 값&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 16.5698%; height: 21px; text-align: center;&quot;&gt;none&lt;/td&gt;
&lt;td style=&quot;width: 45.7558%; height: 21px;&quot;&gt;validation을 하지 않음(기본값)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 16.5698%; height: 21px; text-align: center;&quot;&gt;focus&lt;/td&gt;
&lt;td style=&quot;width: 45.7558%; height: 21px;&quot;&gt;입력 포커스를 얻거나 잃었을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 16.5698%; height: 21px; text-align: center;&quot;&gt;focusin&lt;/td&gt;
&lt;td style=&quot;width: 45.7558%; height: 21px;&quot;&gt;입력 포커스를 얻었을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 16.5698%; height: 21px; text-align: center;&quot;&gt;focusout&lt;/td&gt;
&lt;td style=&quot;width: 45.7558%; height: 21px;&quot;&gt;입력 포커스를 잃었을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 16.5698%; height: 21px; text-align: center;&quot;&gt;key&lt;/td&gt;
&lt;td style=&quot;width: 45.7558%; height: 21px;&quot;&gt;키가 입력되었을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 16.5698%; height: 21px; text-align: center;&quot;&gt;all&lt;/td&gt;
&lt;td style=&quot;width: 45.7558%; height: 21px;&quot;&gt;위 조건을 모두 만족했을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-validate로 지정한 조건을 만족했을 때, -vcmd로 지정한 커맨드를 실행하여 입력 데이터를 확인합니다. -vcmd에는 참 또는 거짓을 반환하는 커맨드를 지정하세요. 커맨드가 참을 반환하면 엔트리의 내용이 갱신됩니다. 커맨드가 거짓을 반환하면 엔트리의 내용은 변경되지 않습니다. 이때, 옵션 -invalidcommand에 커맨드가 설정되어 있다면 그 커맨드가 실행됩니다. &lt;br /&gt;&lt;br /&gt;-vcmd와&amp;nbsp;-invalidcommand로&amp;nbsp;지정한&amp;nbsp;커맨드&amp;nbsp;내에서는&amp;nbsp;위젯&amp;nbsp;내&amp;nbsp;정보를&amp;nbsp;얻기&amp;nbsp;위한&amp;nbsp;방법이&amp;nbsp;준비되어&amp;nbsp;있습니다.&amp;nbsp;%로&amp;nbsp;시작하는&amp;nbsp;문자열은&amp;nbsp;위젯&amp;nbsp;내&amp;nbsp;정보로&amp;nbsp;치환됩니다.&amp;nbsp;체크할&amp;nbsp;데이터는&amp;nbsp;%P로&amp;nbsp;얻을&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;그&amp;nbsp;밖의&amp;nbsp;정보는&amp;nbsp;Tcl/Tk의&amp;nbsp;도움말을&amp;nbsp;참조하세요. &lt;br /&gt;&lt;br /&gt;그럼 간단한 사용 예를 보여드리겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757307015076&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spinbox .s1 -from 1 -to 10 -increment 1 -width 10 \
            -validate key -vcmd {string is integer %P}
spinbox .s2 -value {apple banana cherry grape orange} -width 10 \
            -validate key -vcmd {expr {[string length %P] &amp;lt;= 8}}

pack .s1 .s2 -padx 5 -pady 5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스핀박스 .s1처럼 숫자를 입력하는 경우, 데이터가 숫자인지 확인해두면 편리합니다. 데이터 체크는 Tcl의 커맨드 string을 사용하면 간단합니다. string is class data는 인수 data가 문자 클래스 class로 구성되어 있는지 체크합니다. 문자 클래스란 문자의 종류입니다. 숫자인지 판정할 경우 integer를 지정합니다. &lt;br /&gt;&lt;br /&gt;-validate에는&amp;nbsp;key를&amp;nbsp;지정합니다.&amp;nbsp;이는&amp;nbsp;엔트리에서의&amp;nbsp;키&amp;nbsp;입력에도&amp;nbsp;대응합니다.&amp;nbsp;키&amp;nbsp;입력이&amp;nbsp;있을&amp;nbsp;때마다&amp;nbsp;string&amp;nbsp;is&amp;nbsp;integer로&amp;nbsp;데이터를&amp;nbsp;체크하므로&amp;nbsp;숫자를&amp;nbsp;나타내는&amp;nbsp;문자&amp;nbsp;이외에는&amp;nbsp;입력할&amp;nbsp;수&amp;nbsp;없습니다. &lt;br /&gt;&lt;br /&gt;스핀박스 .s2는 데이터 길이를 string length로 체크합니다. 이로써 8문자보다 긴 데이터를 입력할 수 없습니다.&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/pages/Tk%EC%9D%98-%EC%8A%A4%ED%95%80%EB%B0%95%EC%8A%A4-spinbox</guid>
      <pubDate>Mon, 8 Sep 2025 13:51:06 +0900</pubDate>
    </item>
    <item>
      <title>pix 0.6</title>
      <link>https://ihmin.tistory.com/689</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://github.com/nico-robert/pix&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/nico-robert/pix&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pixie는 Nim 언어로 작성된 기능이 풍부한 2D 그래픽 라이브러리이며, pix는 Tcl/Tk에서 사용가능하게 래핑한 확장 패키지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl/Tk wrapper around Pixie, a full-featured 2D graphics library written in Nim.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;757&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1ztXV/btsQoNPWTnM/iRGWWsjKhwjrM81ZmzRciK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1ztXV/btsQoNPWTnM/iRGWWsjKhwjrM81ZmzRciK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1ztXV/btsQoNPWTnM/iRGWWsjKhwjrM81ZmzRciK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1ztXV%2FbtsQoNPWTnM%2FiRGWWsjKhwjrM81ZmzRciK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;373&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;757&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1757292101414&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package require pix

# Init 'context' with size + color.
set ctx [pix::ctx::new {200 200} &quot;white&quot;]

# Style first rectangle.
pix::ctx::fillStyle $ctx &quot;rgb(0, 0, 255)&quot; ; # blue color
pix::ctx::fillRect $ctx {10 10} {100 100}

# Style second rectangle.
pix::ctx::fillStyle $ctx &quot;rgba(255, 0, 0, 0.5)&quot; ; # red color with alpha 50%
pix::ctx::fillRect $ctx {50 50} {100 100}

# Save context in a image file (*.png|*.bmp|*.qoi|*.ppm)
pix::ctx::writeFile $ctx rectangle.png

# Or display in label by example :
set p [image create photo]
pix::drawSurface $ctx $p
label .l -image $p
pack .l&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/cu6j95/dJMb9LRmTfx/Yc5g7MDpjRdSPpMdftBz11/pix-0.6.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;pix-0.6.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;5.36MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/689</guid>
      <comments>https://ihmin.tistory.com/689#entry689comment</comments>
      <pubDate>Mon, 8 Sep 2025 09:42:30 +0900</pubDate>
    </item>
    <item>
      <title>OTcl 1.14</title>
      <link>https://ihmin.tistory.com/688</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://otcl-tclcl.sourceforge.net/otcl/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://otcl-tclcl.sourceforge.net/otcl/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OTcl은 MIT Object Tcl의 약자로, 객체 지향 프로그래밍을 위해 Tcl/Tk를 확장한 언어입니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;OTcl이&amp;nbsp;다른&amp;nbsp;대안들과&amp;nbsp;비교해&amp;nbsp;가지는&amp;nbsp;주요&amp;nbsp;특징은&amp;nbsp;다음과&amp;nbsp;같습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Tcl처럼 처음부터 동적으로 확장할 수 있도록 설계됨&lt;/li&gt;
&lt;li&gt;다른 언어를 가져오는 대신 Tcl의 문법과 개념을 기반으로 구축됨&lt;/li&gt;
&lt;li&gt;간결하면서도 강력한 객체 프로그래밍 시스템(CLOS, Smalltalk, Self에서 아이디어를 차용)&lt;/li&gt;
&lt;li&gt;꽤 이식성이 높은 구현(핵심을 건드리지 않고 C 코드 2000줄 내외)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OTcl은 네트워크 시뮬레이터인 ns-2에서 쓰이고 있는 것으로 유명합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/MUQDT/dJMb9XYxLrX/JL1qdbprWk6hPAvjutJpek/otcl-src-1.14.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;otcl-src-1.14.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.31MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/툴 (Tool)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/688</guid>
      <comments>https://ihmin.tistory.com/688#entry688comment</comments>
      <pubDate>Fri, 5 Sep 2025 21:37:43 +0900</pubDate>
    </item>
    <item>
      <title>XOTcl 1.6.8</title>
      <link>https://ihmin.tistory.com/687</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://media.wu.ac.at/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://media.wu.ac.at/index.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XOTcl(XOTcl,&amp;nbsp;발음은&amp;nbsp;이그조틱클)은&amp;nbsp;MIT의&amp;nbsp;OTcl을&amp;nbsp;기반으로&amp;nbsp;한&amp;nbsp;객체&amp;nbsp;지향&amp;nbsp;스크립트&amp;nbsp;언어로,&amp;nbsp;여러&amp;nbsp;가지&amp;nbsp;새로운&amp;nbsp;개념을&amp;nbsp;추가했습니다.&amp;nbsp;원래&amp;nbsp;XOTcl은&amp;nbsp;디자인&amp;nbsp;패턴의&amp;nbsp;구현을&amp;nbsp;지원하는&amp;nbsp;언어를&amp;nbsp;개발하기&amp;nbsp;위해&amp;nbsp;만들어졌으며,&amp;nbsp;디자인&amp;nbsp;패턴을&amp;nbsp;런타임에&amp;nbsp;추가하거나&amp;nbsp;제거할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이러한&amp;nbsp;새로운&amp;nbsp;언어는&amp;nbsp;다양한&amp;nbsp;응용&amp;nbsp;분야에&amp;nbsp;매우&amp;nbsp;유연하게&amp;nbsp;활용될&amp;nbsp;수&amp;nbsp;있었으며,&amp;nbsp;모듈식으로&amp;nbsp;독립적인&amp;nbsp;개념들을&amp;nbsp;조합하거나&amp;nbsp;동적으로&amp;nbsp;변경이&amp;nbsp;필요한&amp;nbsp;경우에&amp;nbsp;특히&amp;nbsp;유용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XOTcl (XOTcl, pronounced exotickle) is an object-oriented scripting language based on MIT's OTcl and adds several novel concepts. Originally, XOTcl was intended to develop language support for the implementation of design patterns, were design patterns can be added or removed at runtime. These new language proved to be highly flexible for w wide range of applications, where a moduluar composition of orthogonal concepts and/or dynamic changes are desired.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;XOTcl의 동기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl과&amp;nbsp;같은&amp;nbsp;스크립트&amp;nbsp;언어는&amp;nbsp;컴포넌트들을&amp;nbsp;연결(glueing)하는&amp;nbsp;데&amp;nbsp;적합하도록&amp;nbsp;설계되었으며,&amp;nbsp;동적&amp;nbsp;확장성(dynamic&amp;nbsp;extensibility),&amp;nbsp;동적&amp;nbsp;타입(dynamic&amp;nbsp;typing)&amp;nbsp;및&amp;nbsp;자동&amp;nbsp;변환(automatic&amp;nbsp;conversion)과&amp;nbsp;같은&amp;nbsp;기능을&amp;nbsp;제공하여&amp;nbsp;빠른&amp;nbsp;애플리케이션&amp;nbsp;개발에&amp;nbsp;매우&amp;nbsp;적합합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scripting languages, like Tcl, are designed for glueing components together, provide features like dynamic extensibility and dynamic typing with automatic conversion, that make them well suited for rapid application development.&lt;br /&gt;&lt;br /&gt;XOTcl의 기본 객체 시스템은 OTcl에서 채택되었습니다. 이 객체 시스템을 통해 객체, 클래스, 메타클래스를 정의할 수 있습니다. 클래스는 다른 객체를 관리하는 특수한 객체입니다. &amp;ldquo;관리한다&amp;rdquo;는 것은 클래스가 자신의 인스턴스 생성과 소멸을 제어하고, 인스턴스들이 접근할 수 있는 메서드 저장소(repository)를 포함한다는 의미입니다. 모든 객체는 객체별로 고유한 메서드로 확장될 수 있습니다. XOTcl은 단일 상속(single inheritance)과 다중 상속(multiple inheritance)을 지원합니다. 클래스 및 슈퍼클래스 관계를 포함한 XOTcl의 모든 관계는 완전히 동적이며, 분석(introspection)이 가능합니다. 명시적으로 호출할 메서드 이름을 지정하지 않고 메서드 체이닝(method chaining)을 통해, 메서드 이름 결정의 모호함이 방지됩니다. 이 방식으로 가려진(shadowed) 메서드도 현재 메서드 실행에 &amp;ldquo;혼합(mixed into)&amp;rdquo;될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The basic object system of XOTcl is adopted from OTcl. The object system enables us to define objects, classes, and meta-classes. Classes are special objects with the purpose of managing other objects. ``Managing'' means that a class controls the creation and destruction of its instances and that it contains a repository of methods accessible for the instances. Every object may be enhanced with object-specific methods. XOTcl supports single and multiple inheritance. All relationships in XOTcl, including class and superclass relationships, are completely dynamic and can be introspected. Through method chaining without explicit naming of the intended method, ambiguities in name resolution of methods are avoided. This way a shadowed method can be ``mixed into'' the execution of the current method.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Example&lt;/h3&gt;
&lt;pre id=&quot;code_1757075344746&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; Object counter

 counter set count 0

 counter proc add { val } {
  my set count [expr [my set count]  + $val] 
 } 

 counter proc decr { val } {
  my set count [expr [my set count] - $val]
 }

 counter add 3
 counter decr 1&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Change Log&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;2014-04-29&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;Release&amp;nbsp;of&amp;nbsp;XOTcl&amp;nbsp;1.6.8 &lt;br /&gt;&lt;br /&gt;2014-04-29&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;some&amp;nbsp;more&amp;nbsp;cleanup&amp;nbsp;of&amp;nbsp;autoconf&amp;nbsp;(more&amp;nbsp;quoting,&amp;nbsp;remove&amp;nbsp;obsolete&amp;nbsp;file,&amp;nbsp;use&amp;nbsp;recent&amp;nbsp;install-sh) &lt;br /&gt;*&amp;nbsp;try&amp;nbsp;to&amp;nbsp;stick&amp;nbsp;closer&amp;nbsp;to&amp;nbsp;current&amp;nbsp;tcl&amp;nbsp;conventions &lt;br /&gt;&lt;br /&gt;2014-04-29&amp;nbsp;&amp;lt;stefan.sobernig@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;unix/tclAppInit.c:&amp;nbsp;Fix&amp;nbsp;one&amp;nbsp;more&amp;nbsp;compiler&amp;nbsp;warning:&amp;nbsp;undeclared&amp;nbsp;Xotcl_Init() &lt;br /&gt;*&amp;nbsp;Removing&amp;nbsp;configure&amp;nbsp;artifact,&amp;nbsp;otherwise&amp;nbsp;lintian&amp;nbsp;complains &lt;br /&gt;*&amp;nbsp;Makefile.in:&amp;nbsp;LDFLAGS&amp;nbsp;must&amp;nbsp;be&amp;nbsp;referenced&amp;nbsp;differently&amp;nbsp;under&amp;nbsp;TEA &lt;br /&gt;*&amp;nbsp;fixed&amp;nbsp;&quot;make&amp;nbsp;install&quot;&amp;nbsp;problem,&amp;nbsp;fix&amp;nbsp;build&amp;nbsp;problem&amp;nbsp;for&amp;nbsp;xowish &lt;br /&gt;&lt;br /&gt;2014-04-28&amp;nbsp;&amp;lt;stefan.sobernig@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;library/xml/TclExpat-1.1/xmltok_impl.c:&amp;nbsp;fix&amp;nbsp;for&amp;nbsp;CVE-2009-3720 &lt;br /&gt;&lt;br /&gt;2014-04-25&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;follow&amp;nbsp;modern&amp;nbsp;autoconf&amp;nbsp;conventions &lt;br /&gt;*&amp;nbsp;configure.a:&amp;nbsp;use&amp;nbsp;TEA&amp;nbsp;3.9 &lt;br /&gt;*&amp;nbsp;use&amp;nbsp;new&amp;nbsp;tcl.m4 &lt;br /&gt;*&amp;nbsp;Makefile.in:&amp;nbsp;remove&amp;nbsp;hard-coded&amp;nbsp;&quot;-rdynamic&quot;&amp;nbsp;from&amp;nbsp;build&amp;nbsp;of&amp;nbsp;xotclsh &lt;br /&gt;and&amp;nbsp;xowish &lt;br /&gt;*&amp;nbsp;generic/xotclTrace.c:&amp;nbsp;remove&amp;nbsp;obsolete&amp;nbsp;test &lt;br /&gt;&lt;br /&gt;2014-04-24&amp;nbsp;&amp;lt;stefan.sobernig@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;Makefile.in:&amp;nbsp;Make&amp;nbsp;sure&amp;nbsp;that&amp;nbsp;xotclsh&amp;nbsp;+&amp;nbsp;xowish&amp;nbsp;are&amp;nbsp;explicitly&amp;nbsp;linked &lt;br /&gt;against&amp;nbsp;libtclstub*.so,&amp;nbsp;rather&amp;nbsp;than&amp;nbsp;libtcl*.so.&amp;nbsp;Otherwise,&amp;nbsp;building &lt;br /&gt;with&amp;nbsp;--with-xotclsh&amp;nbsp;+&amp;nbsp;--with-xowish&amp;nbsp;fails&amp;nbsp;starting&amp;nbsp;with&amp;nbsp;8.6&amp;nbsp;(which &lt;br /&gt;effectively&amp;nbsp;hides&amp;nbsp;the&amp;nbsp;various&amp;nbsp;stub&amp;nbsp;structures&amp;nbsp;in&amp;nbsp;libtcl*.so). &lt;br /&gt;*&amp;nbsp;AppInit.c:&amp;nbsp;Use&amp;nbsp;the&amp;nbsp;stubbed&amp;nbsp;variant&amp;nbsp;of&amp;nbsp;Tcl_Init(). &lt;br /&gt;*&amp;nbsp;Tested&amp;nbsp;under&amp;nbsp;8.6&amp;nbsp;(fossil&amp;nbsp;trunk&amp;nbsp;as&amp;nbsp;of&amp;nbsp;commit&amp;nbsp;date)&amp;nbsp;and&amp;nbsp;8.5&amp;nbsp;(fossil &lt;br /&gt;core-8-5-branch&amp;nbsp;as&amp;nbsp;of&amp;nbsp;commit&amp;nbsp;date). &lt;br /&gt;Thanks&amp;nbsp;to&amp;nbsp;Sergei&amp;nbsp;Golovan&amp;nbsp;(Debian&amp;nbsp;Tcl/Tk&amp;nbsp;Package&amp;nbsp;Maintainers)&amp;nbsp;for &lt;br /&gt;reporting&amp;nbsp;the&amp;nbsp;issue&amp;nbsp;and&amp;nbsp;an&amp;nbsp;initial&amp;nbsp;patch&amp;nbsp;(see&amp;nbsp;Debian&amp;nbsp;bug&amp;nbsp;#724816). &lt;br /&gt;&lt;br /&gt;2013-07-16&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;library/actiweb/HttpPlace.xotcl:&amp;nbsp;add&amp;nbsp;URL&amp;nbsp;query&amp;nbsp;variables&amp;nbsp;as &lt;br /&gt;arguments &lt;br /&gt;&lt;br /&gt;2013-06-23&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;make&amp;nbsp;version&amp;nbsp;management&amp;nbsp;simpler&amp;nbsp;and&amp;nbsp;freeze&amp;nbsp;XOTcl&amp;nbsp;1.*&amp;nbsp;versions&amp;nbsp;In &lt;br /&gt;order&amp;nbsp;to&amp;nbsp;avoid&amp;nbsp;bad&amp;nbsp;interactions&amp;nbsp;between&amp;nbsp;XOTcl&amp;nbsp;1.0&amp;nbsp;and&amp;nbsp;XOTcl&amp;nbsp;2.0 &lt;br /&gt;the&amp;nbsp;version&amp;nbsp;dependency&amp;nbsp;in&amp;nbsp;1.0&amp;nbsp;where&amp;nbsp;changed&amp;nbsp;to&amp;nbsp;&quot;package&amp;nbsp;require &lt;br /&gt;-exact&amp;nbsp;...&amp;nbsp;1.0&quot;&amp;nbsp;where&amp;nbsp;possible,&amp;nbsp;and&amp;nbsp;the&amp;nbsp;provides&amp;nbsp;where&amp;nbsp;upgraded&amp;nbsp;to &lt;br /&gt;1.0&amp;nbsp;in&amp;nbsp;most&amp;nbsp;cases &lt;br /&gt;*&amp;nbsp;make&amp;nbsp;sure&amp;nbsp;that&amp;nbsp;packages&amp;nbsp;from&amp;nbsp;XOTcl&amp;nbsp;1&amp;nbsp;require&amp;nbsp;XOTcl&amp;nbsp;1 &lt;br /&gt;*&amp;nbsp;generic/xotcl.c:&amp;nbsp;code&amp;nbsp;cleanup &lt;br /&gt;&lt;br /&gt;2013-03-26&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;doc/langRef.xotcl:&amp;nbsp;update&amp;nbsp;documentation &lt;br /&gt;&lt;br /&gt;2012-10-13&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;Make&amp;nbsp;sure&amp;nbsp;to&amp;nbsp;NS_EXPORT&amp;nbsp;Ns_ModuleVersion&amp;nbsp;for&amp;nbsp;people&amp;nbsp;using&amp;nbsp;still &lt;br /&gt;the&amp;nbsp;old-style&amp;nbsp;aolserver&amp;nbsp;module. &lt;br /&gt;&lt;br /&gt;2012-01-16&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;xotcl.c&amp;nbsp;Extend&amp;nbsp;backport&amp;nbsp;of&amp;nbsp;handling&amp;nbsp;of&amp;nbsp;dashes&amp;nbsp;in&amp;nbsp;XOTcl's &lt;br /&gt;configure&amp;nbsp;method&amp;nbsp;to&amp;nbsp;perform&amp;nbsp;a&amp;nbsp;more&amp;nbsp;eager&amp;nbsp;search&amp;nbsp;for&amp;nbsp;command &lt;br /&gt;begins.&amp;nbsp;Extended&amp;nbsp;regression&amp;nbsp;test &lt;br /&gt;&lt;br /&gt;2012-01-14&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;xotcl.c&amp;nbsp;Don't&amp;nbsp;overwrite&amp;nbsp;error&amp;nbsp;messages&amp;nbsp;from&amp;nbsp;__unknown&amp;nbsp;handler&amp;nbsp;in &lt;br /&gt;several&amp;nbsp;situations&amp;nbsp;(superclass,&amp;nbsp;parameter&amp;nbsp;class,&amp;nbsp;mixin&amp;nbsp;class) &lt;br /&gt;&lt;br /&gt;2012-01-12&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;xotcl.c&amp;nbsp;Backport&amp;nbsp;from&amp;nbsp;nsf:&amp;nbsp;when&amp;nbsp;processing&amp;nbsp;arguments&amp;nbsp;with &lt;br /&gt;leading&amp;nbsp;dashes&amp;nbsp;in&amp;nbsp;&quot;configure&quot;,&amp;nbsp;accept&amp;nbsp;only&amp;nbsp;method&amp;nbsp;names&amp;nbsp;without &lt;br /&gt;spaces.&amp;nbsp;This&amp;nbsp;solves&amp;nbsp;a&amp;nbsp;problem&amp;nbsp;with&amp;nbsp;Tcl8.4&amp;nbsp;+&amp;nbsp;ns_eval&amp;nbsp;where&amp;nbsp;the &lt;br /&gt;output&amp;nbsp;of&amp;nbsp;the&amp;nbsp;serializer&amp;nbsp;could&amp;nbsp;not&amp;nbsp;be&amp;nbsp;processed&amp;nbsp;by&amp;nbsp;eval&amp;nbsp;(a&amp;nbsp;[list &lt;br /&gt;..]&amp;nbsp;was&amp;nbsp;lost). &lt;br /&gt;&lt;br /&gt;2011-12-22&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;Httpd:&amp;nbsp;force&amp;nbsp;GMT&amp;nbsp;dates&amp;nbsp;as&amp;nbsp;required&amp;nbsp;by&amp;nbsp;RFC &lt;br /&gt;&lt;br /&gt;2011-11-12&amp;nbsp;&amp;lt;Gustaf.Neumann@wu-wien.ac.at&amp;gt; &lt;br /&gt;*&amp;nbsp;Removed&amp;nbsp;obsolete&amp;nbsp;CVS-$Ids &lt;br /&gt;*&amp;nbsp;Updated&amp;nbsp;dates&amp;nbsp;of&amp;nbsp;Copyrights &lt;br /&gt;*&amp;nbsp;Removed&amp;nbsp;unneeded&amp;nbsp;c++&amp;nbsp;hints&amp;nbsp;for&amp;nbsp;Emacs&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/RMLQr/dJMb9VNbWSL/xQ49l67Gk9ZFfnlg2jbWs1/xotcl-1.6.8.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;xotcl-1.6.8.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.47MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bDL0cY/dJMb9XRMclL/4EfIW914dtz1mBcJjY9WD1/tutorial.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tutorial.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.26MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/cNPrEJ/dJMb9XRMclM/3RA1X3MeD7amtJg4qARoq1/langRef-xotcl.pdf?attach=1&amp;amp;knm=tfile.pdf&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;langRef-xotcl.pdf&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.26MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <category>xotcl</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/687</guid>
      <comments>https://ihmin.tistory.com/687#entry687comment</comments>
      <pubDate>Fri, 5 Sep 2025 21:26:17 +0900</pubDate>
    </item>
    <item>
      <title>TclOO 1.0.4</title>
      <link>https://ihmin.tistory.com/686</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://core.tcl-lang.org/tcloo/wiki?name=TclOO+Package&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://core.tcl-lang.org/tcloo/wiki?name=TclOO+Package&lt;/a&gt;, &lt;a href=&quot;https://github.com/tcltk/tcloo&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/tcltk/tcloo&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 이 버전은 Tcl 8.5 버전용입니다. 8.6에는 이미 코어로 채택되어 들어가 있는 기능입니다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TclOO 버전 1.0.4 출시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 버전은 Tcl 8.6.5에 포함된 TclOO의 공식 버전과 동일하며, 8.6 런타임이 필요한 일부 기능(특히 코루틴 지원 및 일부 명령의 바이트코드 컴파일 등)은 제외되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;This&amp;nbsp;officially&amp;nbsp;corresponds&amp;nbsp;to&amp;nbsp;the&amp;nbsp;version&amp;nbsp;of&amp;nbsp;TclOO&amp;nbsp;that&amp;nbsp;is&amp;nbsp;included&amp;nbsp;with&amp;nbsp;Tcl&amp;nbsp;8.6.5,&amp;nbsp;except&amp;nbsp;for&amp;nbsp;features&amp;nbsp;(notably&amp;nbsp;coroutine&amp;nbsp;support&amp;nbsp;and&amp;nbsp;bytecode&amp;nbsp;compilation&amp;nbsp;of&amp;nbsp;some&amp;nbsp;commands)&amp;nbsp;that&amp;nbsp;require&amp;nbsp;the&amp;nbsp;8.6&amp;nbsp;runtime.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TclOO: Tcl을 위한 객체 시스템&amp;nbsp;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TclOO는&amp;nbsp;높은&amp;nbsp;성능과&amp;nbsp;최대한의&amp;nbsp;유연성을&amp;nbsp;제공하도록&amp;nbsp;설계된&amp;nbsp;Tcl용&amp;nbsp;객체&amp;nbsp;시스템으로,&amp;nbsp;다른&amp;nbsp;객체&amp;nbsp;시스템의&amp;nbsp;코어&amp;nbsp;역할을&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;만들어졌습니다.&amp;nbsp;클래스&amp;nbsp;자체가&amp;nbsp;하위&amp;nbsp;클래스로&amp;nbsp;확장&amp;nbsp;가능한&amp;nbsp;객체로&amp;nbsp;취급되는&amp;nbsp;단일&amp;nbsp;루트&amp;nbsp;기반&amp;nbsp;클래스&amp;nbsp;시스템을&amp;nbsp;지원하며,&amp;nbsp;다중&amp;nbsp;상속,&amp;nbsp;믹스인(mixin),&amp;nbsp;프로시저와&amp;nbsp;유사한&amp;nbsp;메서드&amp;nbsp;및&amp;nbsp;전달(forwarded)&amp;nbsp;메서드,&amp;nbsp;필터&amp;nbsp;메서드,&amp;nbsp;동적&amp;nbsp;재구성&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;기능을&amp;nbsp;제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TclOO&amp;nbsp;is&amp;nbsp;an&amp;nbsp;object&amp;nbsp;system&amp;nbsp;for&amp;nbsp;Tcl&amp;nbsp;that&amp;nbsp;has&amp;nbsp;been&amp;nbsp;designed&amp;nbsp;to&amp;nbsp;provide&amp;nbsp;high&amp;nbsp;performance&amp;nbsp;while&amp;nbsp;still&amp;nbsp;allowing&amp;nbsp;as&amp;nbsp;much&amp;nbsp;flexibility&amp;nbsp;as&amp;nbsp;possible,&amp;nbsp;and&amp;nbsp;to&amp;nbsp;be&amp;nbsp;a&amp;nbsp;core&amp;nbsp;for&amp;nbsp;other&amp;nbsp;object&amp;nbsp;systems.&amp;nbsp;It&amp;nbsp;supports&amp;nbsp;a&amp;nbsp;single-rooted&amp;nbsp;class-based&amp;nbsp;object&amp;nbsp;system&amp;nbsp;where&amp;nbsp;classes&amp;nbsp;are&amp;nbsp;themselves&amp;nbsp;subclassable&amp;nbsp;objects,&amp;nbsp;with&amp;nbsp;multiple&amp;nbsp;inheritance,&amp;nbsp;mixins,&amp;nbsp;procedure-like&amp;nbsp;and&amp;nbsp;forwarded&amp;nbsp;methods,&amp;nbsp;filter&amp;nbsp;methods,&amp;nbsp;dynamic&amp;nbsp;reconfiguration,&amp;nbsp;etc.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;TclOO는&amp;nbsp;방대한&amp;nbsp;클래스&amp;nbsp;라이브러리를&amp;nbsp;제공하지&amp;nbsp;않으며,&amp;nbsp;사용자&amp;nbsp;스크립트에&amp;nbsp;사용을&amp;nbsp;강제하지도&amp;nbsp;않습니다.&amp;nbsp;Tcllib의&amp;nbsp;일부&amp;nbsp;패키지는&amp;nbsp;TclOO를&amp;nbsp;사용하지만,&amp;nbsp;이들&amp;nbsp;역시&amp;nbsp;다른&amp;nbsp;Tcl&amp;nbsp;8.6&amp;nbsp;기능에&amp;nbsp;의존할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;It&amp;nbsp;does&amp;nbsp;not&amp;nbsp;come&amp;nbsp;with&amp;nbsp;a&amp;nbsp;large&amp;nbsp;class&amp;nbsp;library,&amp;nbsp;and&amp;nbsp;it&amp;nbsp;does&amp;nbsp;not&amp;nbsp;force&amp;nbsp;its&amp;nbsp;use&amp;nbsp;upon&amp;nbsp;user&amp;nbsp;scripts.&amp;nbsp;Some&amp;nbsp;of&amp;nbsp;the&amp;nbsp;packages&amp;nbsp;in&amp;nbsp;Tcllib&amp;nbsp;use&amp;nbsp;TclOO,&amp;nbsp;but&amp;nbsp;these&amp;nbsp;may&amp;nbsp;be&amp;nbsp;dependent&amp;nbsp;on&amp;nbsp;other&amp;nbsp;Tcl&amp;nbsp;8.6&amp;nbsp;features.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;TclOO의&amp;nbsp;유산은&amp;nbsp;XOTcl,&amp;nbsp;incr&amp;nbsp;Tcl,&amp;nbsp;Snit&amp;nbsp;등&amp;nbsp;여러&amp;nbsp;객체&amp;nbsp;시스템에서&amp;nbsp;비롯되었으며,&amp;nbsp;C++,&amp;nbsp;Java,&amp;nbsp;Ruby&amp;nbsp;등&amp;nbsp;다른&amp;nbsp;언어의&amp;nbsp;객체&amp;nbsp;시스템&amp;nbsp;경험도&amp;nbsp;반영되어&amp;nbsp;있습니다(각&amp;nbsp;언어와는&amp;nbsp;다소&amp;nbsp;다르지만).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The&amp;nbsp;heritage&amp;nbsp;of&amp;nbsp;TclOO&amp;nbsp;can&amp;nbsp;be&amp;nbsp;traced&amp;nbsp;back&amp;nbsp;to&amp;nbsp;a&amp;nbsp;number&amp;nbsp;of&amp;nbsp;other&amp;nbsp;object&amp;nbsp;systems,&amp;nbsp;notably&amp;nbsp;including&amp;nbsp;XOTcl,&amp;nbsp;incr&amp;nbsp;Tcl,&amp;nbsp;and&amp;nbsp;Snit.&amp;nbsp;It&amp;nbsp;also&amp;nbsp;draws&amp;nbsp;on&amp;nbsp;experience&amp;nbsp;with&amp;nbsp;object&amp;nbsp;systems&amp;nbsp;in&amp;nbsp;other&amp;nbsp;languages&amp;nbsp;like&amp;nbsp;C++,&amp;nbsp;Java&amp;nbsp;and&amp;nbsp;Ruby&amp;nbsp;(despite&amp;nbsp;being&amp;nbsp;somewhat&amp;nbsp;different&amp;nbsp;from&amp;nbsp;each&amp;nbsp;of&amp;nbsp;them).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/dUsiOM/dJMb9Xxtl6l/AcJY2fkdiPoFhATb0zLGF0/tcloo-release_1_0_4.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tcloo-release_1_0_4.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.26MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/686</guid>
      <comments>https://ihmin.tistory.com/686#entry686comment</comments>
      <pubDate>Fri, 5 Sep 2025 17:27:08 +0900</pubDate>
    </item>
    <item>
      <title>ICU를 이용한 파일 인코딩 검출하기</title>
      <link>https://ihmin.tistory.com/685</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;주로 인코딩 감지에 chardet를 써왔는데 감지가 잘 안 되는 경우가 있었음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ICU(International Components for Unicode library)라는 게 있어서 테스트해보니 잘 되는 것 같음.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;간단하고&amp;nbsp;빠르게&amp;nbsp;인코딩&amp;nbsp;감지&amp;nbsp;&amp;rarr;&amp;nbsp;chardet &lt;br /&gt;정확하고&amp;nbsp;다양한&amp;nbsp;텍스트/국제화&amp;nbsp;지원&amp;nbsp;&amp;rarr;&amp;nbsp;ICU&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 ICU를 이용한 입력한 파일의 인코딩 감지 코드.&lt;/p&gt;
&lt;pre id=&quot;code_1757050970554&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unicode/ucsdet.h&amp;gt;
#include &amp;lt;fstream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;iostream&amp;gt;

std::string detectEncoding(const std::string&amp;amp; filename) {
    // 파일 내용 읽기
    std::ifstream file(filename, std::ios::binary);
    if (!file) {
        throw std::runtime_error(&quot;파일을 열 수 없습니다: &quot; + filename);
    }
    std::vector&amp;lt;char&amp;gt; buffer((std::istreambuf_iterator&amp;lt;char&amp;gt;(file)), std::istreambuf_iterator&amp;lt;char&amp;gt;());

    // ICU CharsetDetector 생성
    UErrorCode status = U_ZERO_ERROR;
    UCharsetDetector* csd = ucsdet_open(&amp;amp;status);
    if (U_FAILURE(status)) {
        throw std::runtime_error(&quot;UCharsetDetector 생성 실패&quot;);
    }

    // 파일 데이터 설정
    ucsdet_setText(csd, buffer.data(), buffer.size(), &amp;amp;status);
    if (U_FAILURE(status)) {
        ucsdet_close(csd);
        throw std::runtime_error(&quot;텍스트 설정 실패&quot;);
    }

    // 인코딩 검출
    const UCharsetMatch* match = ucsdet_detect(csd, &amp;amp;status);
    if (U_FAILURE(status) || !match) {
        ucsdet_close(csd);
        throw std::runtime_error(&quot;인코딩 검출 실패&quot;);
    }

    // 결과 가져오기
    const char* encoding = ucsdet_getName(match, &amp;amp;status);
    std::string result = encoding ? encoding : &quot;unknown&quot;;

    ucsdet_close(csd);
    return result;
}

int main(int argc, char* argv[]) {
    if (argc &amp;lt; 2) {
        std::cerr &amp;lt;&amp;lt; &quot;사용법: &quot; &amp;lt;&amp;lt; argv[0] &amp;lt;&amp;lt; &quot; &amp;lt;파일명&amp;gt;&quot; &amp;lt;&amp;lt; std::endl;
        return 1;
    }
    try {
        std::string encoding = detectEncoding(argv[1]);
        std::cout &amp;lt;&amp;lt; &quot;검출된 인코딩: &quot; &amp;lt;&amp;lt; encoding &amp;lt;&amp;lt; std::endl;
    } catch (std::exception&amp;amp; e) {
        std::cerr &amp;lt;&amp;lt; &quot;오류: &quot; &amp;lt;&amp;lt; e.what() &amp;lt;&amp;lt; std::endl;
        return 1;
    }
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 컴파일하고 테스트..&lt;/p&gt;
&lt;pre id=&quot;code_1757051005978&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ g++ detect_encoding_with_icu.cpp -licuuc -licudt -licuin

$ ./a.exe ./detect_encoding_with_icu.cpp
검출된 인코딩: EUC-KR&lt;/code&gt;&lt;/pre&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>chardet</category>
      <category>Detect</category>
      <category>encoding</category>
      <category>ICU</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/685</guid>
      <comments>https://ihmin.tistory.com/685#entry685comment</comments>
      <pubDate>Fri, 5 Sep 2025 14:47:15 +0900</pubDate>
    </item>
    <item>
      <title>Tcl의 로고가 깃털인 이유</title>
      <link>https://ihmin.tistory.com/684</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;125&quot; data-origin-height=&quot;265&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q34rL/dJMb9XEeWdA/1ss4tnBW4J0n7RZk1BTzhk/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q34rL/dJMb9XEeWdA/1ss4tnBW4J0n7RZk1BTzhk/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q34rL/dJMb9XEeWdA/1ss4tnBW4J0n7RZk1BTzhk/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq34rL%2FdJMb9XEeWdA%2F1ss4tnBW4J0n7RZk1BTzhk%2Ftfile.svg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;66&quot; height=&quot;140&quot; data-origin-width=&quot;125&quot; data-origin-height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl의 로고가 깃털인 이유는 &amp;ldquo;Tcl(티클)&amp;rdquo;의 발음이 영어 &amp;ldquo;tickle&amp;rdquo;과 비슷하기 때문입니다. 이 발음에서 착안하여, &amp;ldquo;tickle&amp;rdquo;이 영어로 &amp;ldquo;간지럽히다&amp;rdquo;라는 뜻이고, 간지럽히는 데 흔히 깃털을 사용하죠. 그래서 Tcl의 로고도 깃털 모양이 된 것입니다. &lt;br /&gt;&lt;br /&gt;즉, Tcl(Tool Command Language)의 이름이 &amp;ldquo;tickle&amp;rdquo;처럼 들려서, 이를 시각적으로 표현하기 위해 깃털이 로고가 되었습니다. 이는 공식 문서와 커뮤니티에서도 유머러스하게 설명되고 있는 부분입니다.&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/팁 (Tip)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/684</guid>
      <comments>https://ihmin.tistory.com/684#entry684comment</comments>
      <pubDate>Fri, 5 Sep 2025 12:37:07 +0900</pubDate>
    </item>
    <item>
      <title>파이프 강좌가 등록되었습니다.</title>
      <link>https://ihmin.tistory.com/notice/683</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl에서 파이프(pipe)를 사용하는 방법에 대한 강좌가 등록 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tcltk.co.kr/pages/Tcl%EC%9D%98-%ED%8C%8C%EC%9D%B4%ED%94%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tcl의 파이프&lt;/a&gt;&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/notice/683</guid>
      <pubDate>Fri, 5 Sep 2025 10:54:52 +0900</pubDate>
    </item>
    <item>
      <title>Tcl의 파이프</title>
      <link>https://ihmin.tistory.com/pages/Tcl%EC%9D%98-%ED%8C%8C%EC%9D%B4%ED%94%84</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;파이프(pipe)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl/Tk에서&amp;nbsp;외부&amp;nbsp;명령을&amp;nbsp;실행할&amp;nbsp;때,&amp;nbsp;exec&amp;nbsp;명령뿐만&amp;nbsp;아니라&amp;nbsp;open&amp;nbsp;명령을&amp;nbsp;사용하여&amp;nbsp;파이프라인을&amp;nbsp;오픈할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이&amp;nbsp;경우,&amp;nbsp;파이프를&amp;nbsp;통해&amp;nbsp;실행된&amp;nbsp;외부&amp;nbsp;명령과&amp;nbsp;데이터의&amp;nbsp;주고받기가&amp;nbsp;가능합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;커맨드라인의 파이프&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셸의 커맨드라인에서 사용하는 파이프는 한 프로그램의 표준 출력에서 출력된 데이터를 다른 프로그램의 표준 입력으로 전달하는 역할을 합니다. 데이터를 물의 흐름으로 생각하면, 실제로 파이프를 사용해 프로그램을 연결하여 데이터를 흘려보내는 것입니다. 파이프는 UNIX 계열 OS뿐만 아니라, MS-DOS에도 있는 기능입니다. 예를 들어, 다음과 같은 예를 보세요.&lt;/p&gt;
&lt;pre id=&quot;code_1757036260882&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; sort file.dat | uniq&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sort는 텍스트 파일을 정렬하는 명령이고, uniq는 중복된 행을 삭제하는 명령입니다. | 기호가 파이프를 나타내며, 이것으로 sort와 uniq가 파이프로 연결됩니다. &lt;br /&gt;&lt;br /&gt;파이프의 제어는 셸(MS-DOS라면 command.com)이 담당합니다. 하지만 MS-DOS처럼 여러 프로그램을 동시에 실행할 수 없는 환경에서는 다음과 같이 파일을 경유하여 데이터가 전달됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757036282481&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sort file.dat &amp;gt; temp
uniq &amp;lt; temp
del temp&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 MS-DOS의 경우, 파이프라고 해도 배치 처리와 동일해집니다. &lt;br /&gt;&lt;br /&gt;하지만&amp;nbsp;UNIX&amp;nbsp;계열&amp;nbsp;OS나&amp;nbsp;Windows처럼&amp;nbsp;여러&amp;nbsp;프로그램을&amp;nbsp;동시에&amp;nbsp;실행할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;환경에서는&amp;nbsp;파일을&amp;nbsp;경유할&amp;nbsp;필요가&amp;nbsp;없습니다.&amp;nbsp;파이프는&amp;nbsp;&quot;큐(queue)&quot;와&amp;nbsp;같은&amp;nbsp;것이라고&amp;nbsp;생각하면&amp;nbsp;됩니다.&amp;nbsp;만약&amp;nbsp;파이프가&amp;nbsp;가득&amp;nbsp;차서&amp;nbsp;데이터를&amp;nbsp;쓸&amp;nbsp;수&amp;nbsp;없다면,&amp;nbsp;OS에&amp;nbsp;의해&amp;nbsp;쓰기&amp;nbsp;측&amp;nbsp;프로그램은&amp;nbsp;휴면&amp;nbsp;상태에&amp;nbsp;들어갑니다.&amp;nbsp;그리고&amp;nbsp;파이프에서&amp;nbsp;데이터가&amp;nbsp;꺼내져&amp;nbsp;써도&amp;nbsp;되는&amp;nbsp;상태가&amp;nbsp;되면,&amp;nbsp;OS가&amp;nbsp;휴면&amp;nbsp;중인&amp;nbsp;프로그램을&amp;nbsp;깨워&amp;nbsp;데이터를&amp;nbsp;파이프에&amp;nbsp;씁니다.&amp;nbsp;파이프가&amp;nbsp;비어있는&amp;nbsp;상태에서&amp;nbsp;데이터를&amp;nbsp;읽으려&amp;nbsp;한다면,&amp;nbsp;반대로&amp;nbsp;읽기&amp;nbsp;측&amp;nbsp;프로그램이&amp;nbsp;휴면&amp;nbsp;상태가&amp;nbsp;됩니다. &lt;br /&gt;&lt;br /&gt;이러한&amp;nbsp;OS의&amp;nbsp;동작으로&amp;nbsp;인해,&amp;nbsp;실행&amp;nbsp;중인&amp;nbsp;프로그램&amp;nbsp;간에&amp;nbsp;파이프를&amp;nbsp;통해&amp;nbsp;데이터를&amp;nbsp;주고받을&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이것을&amp;nbsp;&quot;프로세스&amp;nbsp;간&amp;nbsp;통신&quot;이라고&amp;nbsp;합니다.&amp;nbsp;프로세스는&amp;nbsp;실행&amp;nbsp;중인&amp;nbsp;프로그램이라고&amp;nbsp;생각하면&amp;nbsp;됩니다.&amp;nbsp;파이프를&amp;nbsp;통해&amp;nbsp;양방향으로&amp;nbsp;데이터를&amp;nbsp;주고받는&amp;nbsp;것도&amp;nbsp;가능합니다.&amp;nbsp;프로세스&amp;nbsp;간&amp;nbsp;통신에는&amp;nbsp;여러&amp;nbsp;가지&amp;nbsp;방법이&amp;nbsp;있지만,&amp;nbsp;그중에서도&amp;nbsp;파이프는&amp;nbsp;손쉽게&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;방법입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파이프 사용법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼&amp;nbsp;Tcl에서&amp;nbsp;파이프를&amp;nbsp;사용하는&amp;nbsp;방법을&amp;nbsp;설명하겠습니다.&amp;nbsp;Tcl에서&amp;nbsp;파이프를&amp;nbsp;오픈하려면&amp;nbsp;open&amp;nbsp;명령을&amp;nbsp;사용합니다.&amp;nbsp;open은&amp;nbsp;전달된&amp;nbsp;파일명의&amp;nbsp;첫&amp;nbsp;글자가&amp;nbsp;파이프&amp;nbsp;기호&amp;nbsp;|라면,&amp;nbsp;그&amp;nbsp;인수를&amp;nbsp;파일명이&amp;nbsp;아니라&amp;nbsp;명령으로&amp;nbsp;실행하여&amp;nbsp;파이프를&amp;nbsp;생성합니다.&amp;nbsp;다음&amp;nbsp;예를&amp;nbsp;보세요.&lt;/p&gt;
&lt;pre id=&quot;code_1757036315346&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set f1 [open &quot;|prog1&quot; r]
set f2 [open &quot;|prog2&quot; w]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일과 마찬가지로 파이프를 오픈할 때는 액세스 모드를 지정합니다. 그리고 open은 파이프에 액세스하기 위한 식별자(문자열)를 반환합니다. &lt;br /&gt;&lt;br /&gt;첫&amp;nbsp;번째&amp;nbsp;예는&amp;nbsp;파이프를&amp;nbsp;읽기&amp;nbsp;오픈하는&amp;nbsp;경우입니다.&amp;nbsp;명령&amp;nbsp;prog1을&amp;nbsp;실행하고,&amp;nbsp;표준&amp;nbsp;출력으로&amp;nbsp;출력된&amp;nbsp;데이터가&amp;nbsp;파이프에&amp;nbsp;보내져&amp;nbsp;gets로&amp;nbsp;읽어올&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;다음&amp;nbsp;예는&amp;nbsp;파이프를&amp;nbsp;쓰기&amp;nbsp;오픈하는&amp;nbsp;경우입니다.&amp;nbsp;이&amp;nbsp;경우&amp;nbsp;puts로&amp;nbsp;표준&amp;nbsp;출력에&amp;nbsp;출력된&amp;nbsp;데이터는,&amp;nbsp;파이프를&amp;nbsp;통해&amp;nbsp;실행된&amp;nbsp;명령&amp;nbsp;prog2의&amp;nbsp;표준&amp;nbsp;입력으로&amp;nbsp;보내집니다.&amp;nbsp;마지막에는&amp;nbsp;close&amp;nbsp;명령으로&amp;nbsp;파이프를&amp;nbsp;닫는&amp;nbsp;것을&amp;nbsp;잊지&amp;nbsp;마세요. &lt;br /&gt;&lt;br /&gt;그리고&amp;nbsp;Tcl에서는&amp;nbsp;파이프를&amp;nbsp;양방향(읽기/쓰기&amp;nbsp;모두)으로&amp;nbsp;오픈할&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;이&amp;nbsp;경우,&amp;nbsp;실행된&amp;nbsp;프로그램과&amp;nbsp;양방향으로&amp;nbsp;데이터를&amp;nbsp;주고받을&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;다음&amp;nbsp;예를&amp;nbsp;보세요.&lt;/p&gt;
&lt;pre id=&quot;code_1757036332618&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set f3 [open &quot;|prog3&quot; r+]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액세스 모드 r이나 w 뒤에 +를 붙이면 갱신 모드가 되어, 입력과 출력을 모두 할 수 있게 됩니다. 파이프의 경우 r+와 w+ 어느 쪽도 상관없지만, 일반 파일에서 갱신 모드를 지정할 때는 r과 w의 차이에 주의하세요. r+는 파일이 존재하지 않으면 에러가 발생합니다. 또한 w+로 기존 파일을 오픈하면 길이를 0으로 잘라내기 때문에, 그 파일의 내용이 사라집니다. &lt;br /&gt;&lt;br /&gt;또,&amp;nbsp;파이프를&amp;nbsp;사용할&amp;nbsp;때는&amp;nbsp;출력&amp;nbsp;데이터의&amp;nbsp;&quot;버퍼링&quot;에도&amp;nbsp;주의해야&amp;nbsp;합니다.&amp;nbsp;일반적으로&amp;nbsp;데이터&amp;nbsp;입출력은&amp;nbsp;1바이트&amp;nbsp;단위로&amp;nbsp;하면&amp;nbsp;효율이&amp;nbsp;나쁘기&amp;nbsp;때문에,&amp;nbsp;데이터를&amp;nbsp;모으는&amp;nbsp;버퍼를&amp;nbsp;준비하는&amp;nbsp;것이&amp;nbsp;보통입니다.&amp;nbsp;데이터를&amp;nbsp;출력할&amp;nbsp;때는&amp;nbsp;버퍼에&amp;nbsp;데이터를&amp;nbsp;모아두었다가, &lt;br /&gt;&lt;br /&gt;버퍼가&amp;nbsp;가득&amp;nbsp;차면&amp;nbsp;그&amp;nbsp;내용을&amp;nbsp;비웁니다.&amp;nbsp;C&amp;nbsp;언어의&amp;nbsp;표준&amp;nbsp;입출력&amp;nbsp;라이브러리에는&amp;nbsp;버퍼링&amp;nbsp;기능이&amp;nbsp;내장되어&amp;nbsp;있고,&amp;nbsp;Tcl/Tk도&amp;nbsp;입출력은&amp;nbsp;버퍼링되어&amp;nbsp;있습니다.&amp;nbsp;이&amp;nbsp;때문에&amp;nbsp;puts로&amp;nbsp;데이터를&amp;nbsp;출력만&amp;nbsp;해서는&amp;nbsp;데이터를&amp;nbsp;프로그램에&amp;nbsp;보낼&amp;nbsp;수&amp;nbsp;없는&amp;nbsp;경우도&amp;nbsp;있습니다. &lt;br /&gt;데이터를 프로그램에 보내려면, 버퍼의 내용을 비우는 명령 flush를 사용하세요. 혹은 fconfigure 명령으로 버퍼링 모드를 변경해도 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;fconfigure 식별자 -buffering 지정 -buffersize 바이트수&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;full : 버퍼가 가득 차면 flush&lt;/li&gt;
&lt;li&gt;line : 줄바꿈 문자마다 flush&lt;/li&gt;
&lt;li&gt;none&amp;nbsp;:&amp;nbsp;출력&amp;nbsp;명령이&amp;nbsp;실행될&amp;nbsp;때마다&amp;nbsp;flush&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵션 -buffering의 기본값은 full로 설정되어 있습니다. 버퍼 크기는 옵션 -buffersize로 변경할 수 있습니다. &lt;br /&gt;&lt;br /&gt;줄바꿈 문자를 만났을 때 버퍼를 flush하는 동작을 &quot;라인 버퍼링&quot;이라고 합니다. 일반적으로 표준 출력의 동작은 라인 버퍼링이지만, 화면에 출력하지 않을 때, 예를 들어 파일로 리디렉션하거나 파이프에 연결되어 있을 때는 풀 버퍼링으로 바꾸는 프로그램도 있습니다. Tcl/Tk 측에서 데이터를 보내도, 상대 프로그램이 출력을 버퍼링하기 때문에 Tcl/Tk 측에서 데이터를 받을 수 없고, 프로그램이 동작하지 않을 수도 있습니다. 간단한 예를 들어보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757036423929&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set f [open &quot;|pipetest&quot; &quot;r+&quot;]
for {set i 0} {$i &amp;lt; 5} {incr i} {
    puts &quot;$i 를 보냅니다\n&quot;
    puts $f $i
    flush $f
    gets $f line
    puts &quot;$line 를 받았습니다&quot;
    after 1000
}
close $f&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;프로그램은&amp;nbsp;tclsh에서&amp;nbsp;동작합니다.&amp;nbsp;처음에&amp;nbsp;파이프를&amp;nbsp;양방향으로&amp;nbsp;오픈합니다.&amp;nbsp;실행하는&amp;nbsp;프로그램은&amp;nbsp;pipetest입니다.&amp;nbsp;이것은&amp;nbsp;C&amp;nbsp;언어로&amp;nbsp;작성합니다.&amp;nbsp;그&amp;nbsp;후&amp;nbsp;1초마다&amp;nbsp;puts로&amp;nbsp;숫자를&amp;nbsp;pipetest에&amp;nbsp;보내고,&amp;nbsp;gets로&amp;nbsp;pipetest로부터&amp;nbsp;데이터를&amp;nbsp;받습니다.&amp;nbsp;데이터를&amp;nbsp;쓴&amp;nbsp;후에는&amp;nbsp;flush로&amp;nbsp;버퍼를&amp;nbsp;비우는&amp;nbsp;것에&amp;nbsp;주의하세요. &lt;br /&gt;&lt;br /&gt;다음과 같이 pipetest.c를 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757036446482&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

#define SIZE 256

int main()
{
  char buffer[SIZE];
  while( fgets( buffer, SIZE, stdin ) != NULL ){
    printf( &quot;%d\n&quot;, atoi( buffer ) * 10 );
    fflush( stdout );
  }
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램의 내용은 간단하며, 표준 입력으로부터 데이터를 받아 정수값으로 변환한 후, 그것을 10배로 하여 표준 출력으로 출력합니다. fflush()는 버퍼를 비우는 함수입니다. &lt;br /&gt;&lt;br /&gt;이&amp;nbsp;프로그램을&amp;nbsp;DOS&amp;nbsp;창에서&amp;nbsp;실행하는&amp;nbsp;경우,&amp;nbsp;fflush()가&amp;nbsp;없어도&amp;nbsp;정상적으로&amp;nbsp;동작합니다.&amp;nbsp;하지만&amp;nbsp;Tcl과&amp;nbsp;파이프를&amp;nbsp;사용해&amp;nbsp;데이터를&amp;nbsp;주고받을&amp;nbsp;때는,&amp;nbsp;표준&amp;nbsp;출력에&amp;nbsp;쓴&amp;nbsp;데이터가&amp;nbsp;버퍼링되기&amp;nbsp;때문에&amp;nbsp;fflush()로&amp;nbsp;버퍼를&amp;nbsp;비우지&amp;nbsp;않으면&amp;nbsp;정상적으로&amp;nbsp;동작하지&amp;nbsp;않습니다.&amp;nbsp;파이프를&amp;nbsp;사용할&amp;nbsp;때는&amp;nbsp;실행하는&amp;nbsp;프로그램의&amp;nbsp;동작에도&amp;nbsp;주의하세요.&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/pages/Tcl%EC%9D%98-%ED%8C%8C%EC%9D%B4%ED%94%84</guid>
      <pubDate>Fri, 5 Sep 2025 10:44:04 +0900</pubDate>
    </item>
    <item>
      <title>값 호출과 참조 호출</title>
      <link>https://ihmin.tistory.com/681</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 함수 호출 방식에는 두 가지가 있습니다. 하나는 &quot;값 호출(call by value)&quot;이고, 다른 하나는 &quot;참조 호출(call by&amp;nbsp;reference)&quot;입니다. 최근의 프로그래밍 언어는 값 호출이 주류이며, C 언어의 함수나 Tcl의 프로시저가 그 예입니다. 반대로 Perl의 서브루틴은 참조 호출 방식입니다. &lt;br /&gt;&lt;br /&gt;값&amp;nbsp;호출의&amp;nbsp;개념은&amp;nbsp;매우&amp;nbsp;간단합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;전달받을 데이터를 저장할 변수(가인수, 매개변수)를 준비한다.&lt;/li&gt;
&lt;li&gt;데이터를 인수에 대입한다.&lt;/li&gt;
&lt;li&gt;함수(프로시저)&amp;nbsp;실행이&amp;nbsp;끝나면&amp;nbsp;가인수를&amp;nbsp;폐기한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;가인수(매개변수)&quot;란, 프로시저를 정의할 때 데이터를 전달받기 위해 설정하는 변수입니다. 이에 반해, 실제로 프로시저를 호출할 때 전달되는 인수를 &quot;실인수&quot;라고 합니다. 값 호출의 경우, 가인수는 지역 변수로 취급됩니다.&lt;br /&gt;&lt;br /&gt;그런데 값 호출로는 불가능한 처리가 있습니다. 예를 들어, 변수의 값을 교환하는 프로시저 swap을 생각해봅시다. 아래의 프로그램을 보세요. &lt;br /&gt;&lt;br /&gt;리스트:&amp;nbsp;값의&amp;nbsp;교환&amp;nbsp;(잘못된&amp;nbsp;예)&lt;/p&gt;
&lt;pre id=&quot;code_1757035651913&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;proc swap {a b} {
  set temp $a
  set a $b
  set b $temp
}

# x와 y의 값 교환
proc foo {} {
    set x 10
    set y 20
    puts &quot;$x $y&quot;
    swap $x $y
    puts &quot;$x $y&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;foo를 실행하면 다음과 같은 결과가 나옵니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757035666401&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% foo
10 20
10 20&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로시저 swap에서는 인수 a, b의 값을 교환하지만, 변수 x, y의 값은 swap을 호출한 후에도 교환되지 않습니다. 이유는 간단합니다. swap의 인수 a, b는 지역 변수이므로 swap 내에서 a와 b를 교환해도 foo의 변수 x와 y를 교환하는 것이 아니기 때문입니다. 프로시저가 값 호출 방식이기 때문에 다른 프로시저의 지역 변수에 접근할 수 없습니다. &lt;br /&gt;&lt;br /&gt;Tcl에서&amp;nbsp;swap을&amp;nbsp;구현하려면&amp;nbsp;upvar&amp;nbsp;명령을&amp;nbsp;사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757035685842&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;upvar [level] otherVar1 myVar1 otherVar2 myVar2 ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;upvar는 다른 프로시저에서 사용 중인 지역 변수(otherVar)를 실행 중인 프로시저에서 사용할 지역 변수(myVar)와 연결해줍니다. 그 결과, myVar에 접근하는 것은 otherVar에 접근하는 것과 같습니다. 즉, myVar의 값을 읽으면 그 값은 otherVar의 값이고, myVar의 값을 변경하면 otherVar도 그 값으로 바뀝니다. &lt;br /&gt;&lt;br /&gt;프로시저&amp;nbsp;지정에는&amp;nbsp;level을&amp;nbsp;사용합니다.&amp;nbsp;기본값은&amp;nbsp;-1로,&amp;nbsp;실행&amp;nbsp;중인&amp;nbsp;프로시저를&amp;nbsp;호출한&amp;nbsp;프로시저가&amp;nbsp;됩니다.&amp;nbsp;예를&amp;nbsp;들어,&amp;nbsp;다음과&amp;nbsp;같이&amp;nbsp;프로시저를&amp;nbsp;호출했다고&amp;nbsp;합시다.&lt;/p&gt;
&lt;pre id=&quot;code_1757035701098&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;          foo1 -&amp;gt; foo2 -&amp;gt; foo3 -&amp;gt; foo4
level   -3      -2      -1      upvar

         (그림: level의 지정)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;foo4에서&amp;nbsp;upvar를&amp;nbsp;사용할&amp;nbsp;경우,&amp;nbsp;level이&amp;nbsp;-1이면&amp;nbsp;foo3이&amp;nbsp;대상이&amp;nbsp;되고,&amp;nbsp;-2면&amp;nbsp;foo2,&amp;nbsp;-3이면&amp;nbsp;foo1이&amp;nbsp;대상이&amp;nbsp;됩니다.&amp;nbsp;그리고&amp;nbsp;foo1에서&amp;nbsp;upvar를&amp;nbsp;사용하면&amp;nbsp;전역&amp;nbsp;변수를&amp;nbsp;접근하게&amp;nbsp;됩니다. &lt;br /&gt;&lt;br /&gt;리스트:&amp;nbsp;값의&amp;nbsp;교환&lt;/p&gt;
&lt;pre id=&quot;code_1757035765185&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;proc swap {a b} {
    upvar $a aa $b bb
    set temp $aa
    set aa $bb
    set bb $temp
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;upvar를 사용하면 swap을 다음과 같이 프로그래밍할 수 있습니다. &lt;br /&gt;&lt;br /&gt;swap을&amp;nbsp;호출할&amp;nbsp;때는&amp;nbsp;변수명을&amp;nbsp;전달해야&amp;nbsp;한다는&amp;nbsp;점에&amp;nbsp;주의하세요.&amp;nbsp;swap에서는&amp;nbsp;전달받은&amp;nbsp;변수명과&amp;nbsp;프로시저&amp;nbsp;내에서&amp;nbsp;사용할&amp;nbsp;지역&amp;nbsp;변수를&amp;nbsp;upvar로&amp;nbsp;연결합니다.&amp;nbsp;인수&amp;nbsp;a로&amp;nbsp;전달받은&amp;nbsp;변수는&amp;nbsp;aa에,&amp;nbsp;인수&amp;nbsp;b로&amp;nbsp;전달받은&amp;nbsp;변수는&amp;nbsp;bb에&amp;nbsp;연결됩니다.&amp;nbsp;예를&amp;nbsp;들어,&amp;nbsp;다음&amp;nbsp;예시를&amp;nbsp;보세요.&lt;/p&gt;
&lt;pre id=&quot;code_1757035782337&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;proc foo {} {
    set x 10
    set y 20
    puts &quot;$x $y&quot;
    swap x y
    puts &quot;$x $y&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1757035794697&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% foo
10 20
20 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우, aa에 접근하는 것은 foo 내의 지역 변수 x를, bb에 접근하는 것은 y를 접근하는 것과 같습니다. 이렇게 해서 foo의 지역 변수 x와 y의 값을 교환할 수 있습니다.&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/팁 (Tip)</category>
      <category>swap</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/681</guid>
      <comments>https://ihmin.tistory.com/681#entry681comment</comments>
      <pubDate>Fri, 5 Sep 2025 10:31:23 +0900</pubDate>
    </item>
    <item>
      <title>Orchestral Suite From My Girl 2</title>
      <link>https://ihmin.tistory.com/679</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1994년 작인 마이걸 1의 후속작 마이걸 2에 삽입된 마지막 곡..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HWoi6/btsQjEtjC9c/rkmwFPbkdmu2XKLwdbES51/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HWoi6/btsQjEtjC9c/rkmwFPbkdmu2XKLwdbES51/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HWoi6/btsQjEtjC9c/rkmwFPbkdmu2XKLwdbES51/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHWoi6%2FbtsQjEtjC9c%2FrkmwFPbkdmu2XKLwdbES51%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;361&quot; height=&quot;260&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 앨범에서 유일한 경음악으로&amp;nbsp;90년대에 상당히 많이 듣고 다니던 곡이다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/457735579&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bH4MQt/hyZIM0MILZ/7BQuIpN6tal0VVyDTzyCs1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/YPs8y/hyZIOYBL9t/KeHuXhsDWG7ISNLE3VkKj1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-play-service=&quot;daum_tistory&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/457735579?service=daum_tistory&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>블로그 (Blog)/잡담 (Smalltalk)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/679</guid>
      <comments>https://ihmin.tistory.com/679#entry679comment</comments>
      <pubDate>Thu, 4 Sep 2025 22:28:21 +0900</pubDate>
    </item>
    <item>
      <title>TclOO 강좌가 등록 되었습니다.</title>
      <link>https://ihmin.tistory.com/notice/678</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl 8.6에서 드디어 코어로 제공된 OO 시스템인 TclOO에 대한 강좌가 등록되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ihmin.tistory.com/pages/TclOO%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%98%A4%EB%B8%8C%EC%A0%9D%ED%8A%B8-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TclOO를&amp;nbsp;이용한&amp;nbsp;객체&amp;nbsp;지향&amp;nbsp;프로그래밍&lt;/a&gt;&lt;/p&gt;</description>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/notice/678</guid>
      <pubDate>Wed, 3 Sep 2025 22:30:00 +0900</pubDate>
    </item>
    <item>
      <title>리눅스매거진 2004년 1월에 실렸던 인터뷰 기사</title>
      <link>https://ihmin.tistory.com/677</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;아래 기사는 리눅스매거진 2004년 1월에 실렸던 기사입니다. 이젠.. 추억이 되었네요..&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;대한민국&amp;nbsp;Tcl/Tk&amp;nbsp;사용자&amp;nbsp;그룹의&amp;nbsp;리더&amp;nbsp;:&amp;nbsp;민인학&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;347&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yFTOC/btsQhwBkLJ5/U7jrK3dIKfZqrJdtc0JIL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yFTOC/btsQhwBkLJ5/U7jrK3dIKfZqrJdtc0JIL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yFTOC/btsQhwBkLJ5/U7jrK3dIKfZqrJdtc0JIL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyFTOC%2FbtsQhwBkLJ5%2FU7jrK3dIKfZqrJdtc0JIL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;188&quot; height=&quot;173&quot; data-origin-width=&quot;347&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Tcl/Tk는 분명 우리 리눅서에게는 낯설지 않은 스크립트 언어이다. (지금 당장 당신의 리눅스 시스템에 Tcl/Tk 패키지가 설치되어 있는 것을 확인해 보라!) 다만 리눅스 세계에 발을 들여놓으며 귀 따갑게 들어왔던 낙타와 뱀(편집자주 익히 알다시피 O'Reilly에서 출판한 서적의 표지를 장식하는 동물들은 IT 세계에서 해당 기술을 상징하는 심벌로 기억되어 왔다. 낙타와 뱀은 각각 스크립트 언어인 Perl과 Python을 상징한다. 참고로 Tcl/Tk를 상징하는 심벌은 깃털이다. 아파치 웹 서버의 심벌 역시 깃털이라서 혼란스러울 지도 모르겠다. 이 차이는 아파치 웹 서버의 깃털이 옆으로 뉘어져 있는 것에 비해 Tcl/Tk의 깃털은 바짝 세워져 있는 것으로 구분할 수 있다.)에 대한 예찬론으로 &amp;lsquo;미안하지만 잠시 기억 뒤편에&amp;rsquo; 접어두었을 뿐 Tcl/Tk는 당신의 리눅스 시스템에서 언제든지 Standby 상태일 것이다. 이제 잊혔던 서랍장을 열고 Tcl/Tk와 만나러 떠나보자. 당신의 여정에 대한민국 Tcl/Tk 사용자 그룹의 리더 &amp;lsquo;민인학&amp;rsquo;씨가 함께 할 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : 대략적인 자기소개를 부탁합니다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고향은&amp;nbsp;경기도&amp;nbsp;가평이며,&amp;nbsp;대전에서&amp;nbsp;직장생활중인&amp;nbsp;27살의&amp;nbsp;프로그래머입니다.&amp;nbsp;현재의&amp;nbsp;직장을&amp;nbsp;다니기&amp;nbsp;전에는&amp;nbsp;하이닉스&amp;nbsp;반도체에서&amp;nbsp;엔지니어&amp;nbsp;생활을&amp;nbsp;4년&amp;nbsp;정도&amp;nbsp;했습니다.&amp;nbsp;중학교&amp;nbsp;2학년&amp;nbsp;때부터&amp;nbsp;키워&amp;nbsp;온&amp;nbsp;꿈이&amp;nbsp;프로그래머라&amp;nbsp;과감히&amp;nbsp;현재의&amp;nbsp;직장을&amp;nbsp;택했습니다.&amp;nbsp;사실&amp;nbsp;프로그래머가&amp;nbsp;힘든&amp;nbsp;일이지만,&amp;nbsp;그래도&amp;nbsp;제가&amp;nbsp;꿈꿔왔던&amp;nbsp;직업이라&amp;nbsp;만족하며&amp;nbsp;살고&amp;nbsp;있습니다.&amp;nbsp;이런&amp;nbsp;결심을&amp;nbsp;하지&amp;nbsp;않았더라면,&amp;nbsp;리눅스&amp;nbsp;매거진&amp;nbsp;독자&amp;nbsp;여러분을&amp;nbsp;이런&amp;nbsp;자리를&amp;nbsp;통해&amp;nbsp;만나기&amp;nbsp;힘들었을&amp;nbsp;거라&amp;nbsp;생각합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : 현재 어떤 일을 하고 있는가?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재&amp;nbsp;반도체&amp;nbsp;검증&amp;nbsp;툴을&amp;nbsp;제작하는&amp;nbsp;벤처회사인&amp;nbsp;다이나릿&amp;nbsp;시스템(http://www.dynalith.com/)에서&amp;nbsp;연구원으로&amp;nbsp;있으며,&amp;nbsp;유닉스/리눅스/윈도우즈에서&amp;nbsp;동작되는&amp;nbsp;GUI 및&amp;nbsp;기타&amp;nbsp;프로그래밍을&amp;nbsp;담당하고&amp;nbsp;있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : 리눅스와 연관을 맺은 시기, 어떤 일로 리눅스와 친해지게 되었는가?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스를&amp;nbsp;처음&amp;nbsp;접한&amp;nbsp;시기는,&amp;nbsp;1996년경&amp;nbsp;gcc컴파일러를&amp;nbsp;MS-DOS로&amp;nbsp;포팅한&amp;nbsp;32비트&amp;nbsp;컴파일러인&amp;nbsp;djgpp에&amp;nbsp;관심을&amp;nbsp;가지면서,&amp;nbsp;gcc를&amp;nbsp;기본컴파일러를&amp;nbsp;하고&amp;nbsp;있는&amp;nbsp;리눅스를&amp;nbsp;알게&amp;nbsp;되었습니다.&amp;nbsp;DOS상에서의&amp;nbsp;마지막&amp;nbsp;작품은&amp;nbsp;djgpp로&amp;nbsp;만든&amp;nbsp;32비트&amp;nbsp;한글라이브러리이며,&amp;nbsp;1997년에&amp;nbsp;본격적으로&amp;nbsp;리눅스를&amp;nbsp;사용하게 되었습니다.&amp;nbsp;국내&amp;nbsp;그&amp;nbsp;당시에&amp;nbsp;생소했던&amp;nbsp;리눅스를&amp;nbsp;처음&amp;nbsp;접하면서&amp;nbsp;리눅스&amp;nbsp;프로그래밍에&amp;nbsp;관심을&amp;nbsp;갖게 되어,&amp;nbsp;첫&amp;nbsp;작품인&amp;nbsp;GTK+를&amp;nbsp;이용하여,&amp;nbsp;통신프로그래밍인&amp;nbsp;가우에&amp;nbsp;필적할만한(저&amp;nbsp;나름대로의&amp;nbsp;생각입니다.)&amp;nbsp;한글입출력을&amp;nbsp;프로그램&amp;nbsp;자체에&amp;nbsp;내장한&amp;nbsp;통신프로그램을&amp;nbsp;개발했던&amp;nbsp;적이&amp;nbsp;있었습니다.&amp;nbsp;이&amp;nbsp;프로그램으로&amp;nbsp;현재의&amp;nbsp;회사에서&amp;nbsp;근무할&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;되었습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : Tcl/Tk에 대해 자세히 설명해 주세요.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl/Tk는&amp;nbsp;Perl(1977년)다음으로&amp;nbsp;가장&amp;nbsp;오래된,&amp;nbsp;1998년에&amp;nbsp;J.k&amp;nbsp;Ousterhout박사로부터&amp;nbsp;탄생된&amp;nbsp;공개&amp;nbsp;스크립트&amp;nbsp;언어입니다.&amp;nbsp;Tcl/Tk는&amp;nbsp;처음&amp;nbsp;개발당시부터,&amp;nbsp;C언어에&amp;nbsp;짜&amp;nbsp;넣거나,&amp;nbsp;확장성이&amp;nbsp;높은&amp;nbsp;인터프리터형&amp;nbsp;언어로&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;스크립트&amp;nbsp;언어를&amp;nbsp;염두해&amp;nbsp;두고&amp;nbsp;개발되었습니다.&amp;nbsp;Tcl은&amp;nbsp;평이한&amp;nbsp;문법을&amp;nbsp;가지는&amp;nbsp;강력한&amp;nbsp;스크립트&amp;nbsp;언어로,&amp;nbsp;현재&amp;nbsp;Perl,&amp;nbsp;Python과&amp;nbsp;함께&amp;nbsp;초고급(VHLL) 언어로,&amp;nbsp;많은&amp;nbsp;사용자층을&amp;nbsp;확보하고&amp;nbsp;있습니다.&amp;nbsp;Tcl은&amp;nbsp;확장성이&amp;nbsp;높은&amp;nbsp;언어로&amp;nbsp;개발이&amp;nbsp;되었지만,&amp;nbsp;최초에부터&amp;nbsp;현재에&amp;nbsp;이르기까지&amp;nbsp;최대의&amp;nbsp;확장&amp;nbsp;라이브러리는&amp;nbsp;Tk입니다.&amp;nbsp;Tk는&amp;nbsp;Tcl&amp;nbsp;스크립트&amp;nbsp;언어에&amp;nbsp;GUI를&amp;nbsp;접목시켜&amp;nbsp;하나의&amp;nbsp;애플리케이션을&amp;nbsp;완성케&amp;nbsp;해주는&amp;nbsp;Tool&amp;nbsp;Kit입니다.&amp;nbsp;Ousterhout박사는&amp;nbsp;Tcl/Tk가&amp;nbsp;유닉스&amp;nbsp;계산기의&amp;nbsp;GUI애플리케이션을&amp;nbsp;제작하는데&amp;nbsp;적합하다는&amp;nbsp;것을&amp;nbsp;알아차리고,&amp;nbsp;당시에&amp;nbsp;Tcl/Tk의&amp;nbsp;유용한&amp;nbsp;활용사례로&amp;nbsp;공개되어&amp;nbsp;많은&amp;nbsp;사람의&amp;nbsp;이목을&amp;nbsp;집중시킨&amp;nbsp;적이&amp;nbsp;있습니다.&amp;nbsp;Tcl/Tk는&amp;nbsp;Ousterhout박사가&amp;nbsp;Sun으로&amp;nbsp;옮기면서,&amp;nbsp;Sun의&amp;nbsp;수많은&amp;nbsp;개발자들과&amp;nbsp;함께&amp;nbsp;많은&amp;nbsp;기능을&amp;nbsp;보강하여,&amp;nbsp;스크립트&amp;nbsp;언어의&amp;nbsp;강자자리를&amp;nbsp;지키게&amp;nbsp;되었으며,&amp;nbsp;현재는&amp;nbsp;Tcl&amp;nbsp;Developer&amp;nbsp;Exchange(http://tcl.activestate.com/)에서&amp;nbsp;개발을&amp;nbsp;담당하고&amp;nbsp;있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : Perl, Python 등 다른 스크립트 언어와 달리 Tcl/Tk만이 갖는 장점은 무엇이라고 생각합니까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl/Tk는 여타 다른 스크립트 언어와는 달리 배우기가 쉽습니다. 문법이 너무나 간단하여, 배우는데는 일주에서 이주정도면 어느 정도의 애플리케이션을 제작할 수 있으며, 또 수많은 확장패키지(Widget, XML, DATABASE, GRAPHICS, NETWORK, 프로세스 간의 통신(COM) 등이 준비되어 있어, 고 품질의 애플리케이션을 단시간 내에 제작할 수 있기 때문에, 다른 언어로 개발하실 때 보다 개발시간을 상당히 단축시킬 수 있는 이점이 있습니다. 멀티플랫폼에 맞추어 개발된 언어답게 거의 모든 플랫폼에 소스코드의 수정 없이 실행할 수 있으며, Tcl/Tk의 코어(core)에 수정을 가하지 않고, 공유라이브러리(dll, so, sl)를 직접 제작하여 Tcl에서 사용할 수 있어, Tcl/Tk의 다음 버전에 원하는 기능이 추가되길 기다릴 필요가 없습니다. Tcl/Tk는 incr Tcl이라는 확장패키지로 C++의 OO문법을 Tcl문법에 그대로 적용 가능합니다. 현재도 incrTcl은 계속 보완 중이며, Tcl/Tk에서 OO의 문법을 사용할 수 있는 패키지는 incr Tcl 이외에 여러 개가 존재하고 있습니다. Tcl은 바이트 코드를 지원하여 더욱 빠른 실행속도와 소스코드의 은폐 및 멀티폴랫폼상에서의 실행 동작을 자랑하며, 또 제작한 애플리케이션을 Tclkit이나 freewrap을 이용하면 단일의 실행파일로 제작할 수 있어, 제작한 프로그램을 배포 시에 편리하며, 소스코드를 보호할 수 있는 또 다른 장점이 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : Tcl/Tk는 나쁜 언어이니 사용하지 말아라? 라는 유언비어(?)에 대해 한 말씀&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;stm.jpg&quot; data-origin-width=&quot;382&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ocupo/btsQjzLpjbw/DXngoAKVeUYB0XzZVAIf9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ocupo/btsQjzLpjbw/DXngoAKVeUYB0XzZVAIf9k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ocupo/btsQjzLpjbw/DXngoAKVeUYB0XzZVAIf9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Focupo%2FbtsQjzLpjbw%2FDXngoAKVeUYB0XzZVAIf9k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;190&quot; height=&quot;329&quot; data-filename=&quot;stm.jpg&quot; data-origin-width=&quot;382&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리차드 스톨만은 1994년 전자 뉴스상에 'Tcl은 언어구현의 결함 때문에 GNU에서는 채용할 생각이 없다'라고 발표하여 대단한 바람을 불러일으킨 적이 있습니다. 그 당시에는 Tcl은 황당하리 만큼 쉬운 문법과 기본적인 스크립트언어의 기능만을 갖춘, 또 Perl에 비해서 뛰어난 기능이 없는 보통의 스크립트 언어였기 때문이었다고 생각됩니다. 하지만, 리차드 스톨만의 그러한 발언이 있은 후 Tcl/Tk는 많은 변화가 있었습니다. 우선 SUN으로 옮겨가 많은 기능을 보강하며, 필요성이 없는 기능을 과감히 빼버리게 되어, 버전 8대에 와서는 어느 누구도 부인할 수 없는 스크립트언어의 최강자 자리를 지키게 되었습니다. 현재 리차드 스톨만의 발언은 웃으면서 넘길 수 있는 옛날 얘기가 되었을 정도로, 인터프리터 언어와 컴파일러 언어의 양면을 지닌 훌륭한 언어로 자리를 잡고 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q: Tcl/Tk 사용자 그룹에 대해 (http://tcltk.co.kr/)&amp;nbsp;개인적으로&amp;nbsp;어떻게&amp;nbsp;해서&amp;nbsp;Tcl/Tk에&amp;nbsp;관심을&amp;nbsp;가지게&amp;nbsp;되었습니까?&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;617&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mo7sd/btsQjElDjd8/auMskCiyuRSnQKzUcjP2K0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mo7sd/btsQjElDjd8/auMskCiyuRSnQKzUcjP2K0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mo7sd/btsQjElDjd8/auMskCiyuRSnQKzUcjP2K0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMo7sd%2FbtsQjElDjd8%2FauMskCiyuRSnQKzUcjP2K0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;237&quot; height=&quot;143&quot; data-filename=&quot;image.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;617&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl/Tk는 저의 개인적인 필요성으로 알게 된 것은 아닙니다. 저희 회사는 반도체 툴을 제작하는 특성상, 고객들은 멀티플랫폼에서 동작하는 프로그램을 요구하고 있습니다. Tcl/Tk를 사용하기 전에는, 윈도우즈용은 Borland C++ Builder나 VC++로 제작하였으며, 솔라리스/리눅스상에는 gcc와 GTK+를 이용하여 제작하였습니다. 즉 하나의 프로그램을 두세 번 제작하는 어려움을 겪어야만 했습니다. 이때 직장 동료인 양우승 선임 연구원님의 조언으로 Tcl/Tk를 한번 사용해 보는 것이 어떻겠느냐는 제의에 2002년 12월부터 Tcl/Tk를 사용하기 시작했습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q&amp;nbsp;:&amp;nbsp;어떻게&amp;nbsp;해서&amp;nbsp;Tcl/Tk&amp;nbsp;커뮤니티를&amp;nbsp;운영할&amp;nbsp;생각을&amp;nbsp;하셨습니까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl/Tk의&amp;nbsp;우수성을&amp;nbsp;국내에&amp;nbsp;알리고&amp;nbsp;싶어&amp;nbsp;시작하였습니다.&amp;nbsp;Tcl/Tk를&amp;nbsp;1년여&amp;nbsp;사용하면서&amp;nbsp;Tcl/Tk의&amp;nbsp;간결한&amp;nbsp;문법과&amp;nbsp;확장성,&amp;nbsp;또&amp;nbsp;멀티&amp;nbsp;플랫폼에서&amp;nbsp;소스코드의&amp;nbsp;수정&amp;nbsp;없이&amp;nbsp;동작하는&amp;nbsp;매력에&amp;nbsp;되도록이면&amp;nbsp;많은&amp;nbsp;분들께&amp;nbsp;알리고&amp;nbsp;싶었습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : 본인에게 딱히 수익이 생기는 것도 아님에도 불구하고 Tcl/Tk 사용자 그룹을 운영하고 있는 이유는 무엇입니까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는&amp;nbsp;이미&amp;nbsp;많은&amp;nbsp;분들이&amp;nbsp;사용하고&amp;nbsp;있는&amp;nbsp;언어를&amp;nbsp;해서는&amp;nbsp;발전이&amp;nbsp;없다고&amp;nbsp;생각합니다.&amp;nbsp;그래서&amp;nbsp;되도록이면,&amp;nbsp;국내에서만큼은&amp;nbsp;사용하고&amp;nbsp;있지&amp;nbsp;않은&amp;nbsp;언어인&amp;nbsp;Tcl/Tk를&amp;nbsp;저의&amp;nbsp;손끝에서&amp;nbsp;여러&amp;nbsp;많은&amp;nbsp;분들께&amp;nbsp;알리고&amp;nbsp;싶었고,&amp;nbsp;현재도&amp;nbsp;많은&amp;nbsp;분들께&amp;nbsp;알리고&amp;nbsp;싶은&amp;nbsp;것이&amp;nbsp;저의&amp;nbsp;심정입니다.&amp;nbsp;일단&amp;nbsp;저의&amp;nbsp;생각에&amp;nbsp;동참하시는&amp;nbsp;분들이&amp;nbsp;한두&amp;nbsp;분&amp;nbsp;늘어가지만,&amp;nbsp;그렇지&amp;nbsp;못한&amp;nbsp;사람들에게도&amp;nbsp;최선을&amp;nbsp;다해&amp;nbsp;알릴&amp;nbsp;생각입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : 현재 Tcl/Tk 사용자 그룹은 어떻게 운영되고 있으며 그 규모는 어느 정도입니까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재&amp;nbsp;사이트&amp;nbsp;운영에&amp;nbsp;있어서&amp;nbsp;계정은&amp;nbsp;저의&amp;nbsp;사비로&amp;nbsp;충당하고&amp;nbsp;있습니다.&amp;nbsp;제가&amp;nbsp;좋아서&amp;nbsp;시작한일이고,&amp;nbsp;제가&amp;nbsp;발전할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;기회기에,&amp;nbsp;운영에&amp;nbsp;되는&amp;nbsp;돈과&amp;nbsp;시간은&amp;nbsp;크게&amp;nbsp;여념하고&amp;nbsp;있지&amp;nbsp;않습니다.&amp;nbsp;회원수를&amp;nbsp;비교하면,&amp;nbsp;파이썬&amp;nbsp;국내&amp;nbsp;사이트(python.or.kr)에&amp;nbsp;비교해서&amp;nbsp;회원수가&amp;nbsp;많이&amp;nbsp;적은&amp;nbsp;75～80명&amp;nbsp;정도입니다.&amp;nbsp;현재&amp;nbsp;사이트의&amp;nbsp;글들은&amp;nbsp;회원을&amp;nbsp;가입하지&amp;nbsp;않아도&amp;nbsp;글을&amp;nbsp;읽을&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해 놓았기&amp;nbsp;때문에,&amp;nbsp;이로&amp;nbsp;인해서&amp;nbsp;방문하시는&amp;nbsp;분들이&amp;nbsp;회원가입의&amp;nbsp;필요성을&amp;nbsp;느끼지&amp;nbsp;못하는&amp;nbsp;것&amp;nbsp;같습니다.&amp;nbsp;저의&amp;nbsp;사이트&amp;nbsp;목적이&amp;nbsp;회원을&amp;nbsp;늘리는&amp;nbsp;것이&amp;nbsp;아니라,&amp;nbsp;최대한&amp;nbsp;많은&amp;nbsp;분들께&amp;nbsp;Tcl/Tk를&amp;nbsp;알리는&amp;nbsp;것이기&amp;nbsp;때문에,&amp;nbsp;이&amp;nbsp;점은&amp;nbsp;변함이&amp;nbsp;없을&amp;nbsp;것입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : Tcl/Tk 사용자 그룹 운영의 애로점은?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재&amp;nbsp;대부분의&amp;nbsp;글들이&amp;nbsp;제가&amp;nbsp;경험한,&amp;nbsp;또&amp;nbsp;개인적으로&amp;nbsp;Tcl/Tk에&amp;nbsp;대해서&amp;nbsp;공부한&amp;nbsp;강좌들뿐입니다.&amp;nbsp;회사의&amp;nbsp;업무&amp;nbsp;때문에,&amp;nbsp;강좌를&amp;nbsp;예전처럼&amp;nbsp;자주&amp;nbsp;올리진&amp;nbsp;못하지만,&amp;nbsp;회원분들이&amp;nbsp;자발적으로&amp;nbsp;사이트에&amp;nbsp;참여하여&amp;nbsp;주시면,&amp;nbsp;운영하는데&amp;nbsp;많은&amp;nbsp;힘이&amp;nbsp;될&amp;nbsp;것&amp;nbsp;같다는&amp;nbsp;저의&amp;nbsp;작은&amp;nbsp;바램이&amp;nbsp;있습니다.&amp;nbsp;그&amp;nbsp;외에&amp;nbsp;아직&amp;nbsp;까지&amp;nbsp;운영하는데&amp;nbsp;큰&amp;nbsp;문제점이나&amp;nbsp;애로점은&amp;nbsp;없습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : 앞으로 Tcl/Tk 사용자 그룹이 나아가야할 방향은?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는&amp;nbsp;초보적인&amp;nbsp;글들과,&amp;nbsp;확장패키지&amp;nbsp;사용법&amp;nbsp;등,&amp;nbsp;Tcl/Tk를&amp;nbsp;사용하는 데&amp;nbsp;있어&amp;nbsp;다양한&amp;nbsp;정보를&amp;nbsp;다루고&amp;nbsp;있지만,&amp;nbsp;앞으로는&amp;nbsp;필요한&amp;nbsp;공개&amp;nbsp;애플리케이션을&amp;nbsp;저를&amp;nbsp;포함한&amp;nbsp;회원분들이&amp;nbsp;자발적으로&amp;nbsp;참여하여&amp;nbsp;제작하는&amp;nbsp;방향으로,&amp;nbsp;Tcl/Tk의&amp;nbsp;실용성을&amp;nbsp;국내에&amp;nbsp;알릴&amp;nbsp;예정입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : Tcl/Tk를 처음 시작해보려는 Newbie를 위한 조언을 부탁합니다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tcl/Tk는&amp;nbsp;가볍에&amp;nbsp;소설을&amp;nbsp;읽듯이&amp;nbsp;시작할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;언어입니다.&amp;nbsp;Tcl/Tk는&amp;nbsp;Python,&amp;nbsp;Perl등과&amp;nbsp;같은&amp;nbsp;다른&amp;nbsp;스크립트&amp;nbsp;언어에&amp;nbsp;비해서&amp;nbsp;배우기&amp;nbsp;쉬운&amp;nbsp;장점 때문에,&amp;nbsp;일주일정도의&amp;nbsp;시간을&amp;nbsp;투자하시면&amp;nbsp;반드시&amp;nbsp;좋은&amp;nbsp;결과를&amp;nbsp;얻으실 수&amp;nbsp;있으며,&amp;nbsp;언어를&amp;nbsp;하나&amp;nbsp;정복했다는&amp;nbsp;자신감을&amp;nbsp;가지실수&amp;nbsp;있을&amp;nbsp;겁니다.&amp;nbsp;또,&amp;nbsp;앞으로&amp;nbsp;프로그래머가&amp;nbsp;희망인&amp;nbsp;분들이나,&amp;nbsp;현업에&amp;nbsp;종사하시는&amp;nbsp;언어를&amp;nbsp;바꾸고&amp;nbsp;싶으신&amp;nbsp;분들께는&amp;nbsp;최상의&amp;nbsp;언어로&amp;nbsp;자리&amp;nbsp;잡을&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;계기를&amp;nbsp;마련&amp;nbsp;하&amp;nbsp;실수&amp;nbsp;있을&amp;nbsp;겁니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Q : 대한민국 Tcl/Tk 사용자 그룹의 리더로서 리눅스 매거진 독자들에게 한 말씀 및 앞으로의 포부&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇&amp;nbsp;해전부터&amp;nbsp;리눅스를&amp;nbsp;수용하는&amp;nbsp;기업이&amp;nbsp;현재까지&amp;nbsp;계속&amp;nbsp;늘고&amp;nbsp;있습니다.&amp;nbsp;리눅스는&amp;nbsp;오픈소스라는,&amp;nbsp;심지어&amp;nbsp;커널까지&amp;nbsp;공개하고&amp;nbsp;있는&amp;nbsp;최대의&amp;nbsp;무기로,&amp;nbsp;수많은&amp;nbsp;해커들의&amp;nbsp;노력에&amp;nbsp;의해&amp;nbsp;MS사의&amp;nbsp;윈도우즈를&amp;nbsp;능가할&amp;nbsp;정도의&amp;nbsp;운영체제로&amp;nbsp;이미&amp;nbsp;발전되어&amp;nbsp;있습니다.&amp;nbsp;이미&amp;nbsp;어느&amp;nbsp;분야에서는&amp;nbsp;윈도우즈를&amp;nbsp;능가하여,&amp;nbsp;MS가&amp;nbsp;견제하는&amp;nbsp;운영체제&amp;nbsp;자리까지&amp;nbsp;올라섰습니다.&amp;nbsp;이에&amp;nbsp;발맞추어&amp;nbsp;리눅스용&amp;nbsp;제품을&amp;nbsp;원하는&amp;nbsp;고객도&amp;nbsp;늘고&amp;nbsp;있으며,&amp;nbsp;일반&amp;nbsp;사용자와&amp;nbsp;개발자도&amp;nbsp;이미&amp;nbsp;전 세계에&amp;nbsp;두루&amp;nbsp;퍼져&amp;nbsp;있으며,&amp;nbsp;리눅스는&amp;nbsp;상품성의&amp;nbsp;가치를&amp;nbsp;갖춘&amp;nbsp;최고의&amp;nbsp;만능&amp;nbsp;엔터테이너&amp;nbsp;운영체제임이&amp;nbsp;확실하다고&amp;nbsp;생각하고&amp;nbsp;있기에,&amp;nbsp;리눅스의&amp;nbsp;미래를&amp;nbsp;상당히&amp;nbsp;밝게&amp;nbsp;보고&amp;nbsp;있습니다.&amp;nbsp;리눅스&amp;nbsp;매거진&amp;nbsp;독자 여러분이&amp;nbsp;리눅스를&amp;nbsp;사랑하는&amp;nbsp;만큼,&amp;nbsp;한국의&amp;nbsp;리눅스&amp;nbsp;산업은&amp;nbsp;여느&amp;nbsp;어느&amp;nbsp;나라보다도&amp;nbsp;리눅스&amp;nbsp;개발자와&amp;nbsp;리눅스&amp;nbsp;사용자를&amp;nbsp;두루&amp;nbsp;갖춘&amp;nbsp;리눅스&amp;nbsp;강국으로&amp;nbsp;발전되리라&amp;nbsp;믿습니다.&amp;nbsp;끝으로,&amp;nbsp;Tcl/Tk&amp;nbsp;한국&amp;nbsp;사용자&amp;nbsp;사이트는&amp;nbsp;사이트&amp;nbsp;제목에&amp;nbsp;걸맞은,&amp;nbsp;국내&amp;nbsp;최고의&amp;nbsp;Tcl/Tk&amp;nbsp;정보&amp;nbsp;사이트로&amp;nbsp;거듭날&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;최선의&amp;nbsp;노력을&amp;nbsp;다할&amp;nbsp;것입니다.&amp;nbsp;감사합니다.&lt;/p&gt;</description>
      <category>블로그 (Blog)/잡담 (Smalltalk)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/677</guid>
      <comments>https://ihmin.tistory.com/677#entry677comment</comments>
      <pubDate>Tue, 2 Sep 2025 23:25:55 +0900</pubDate>
    </item>
    <item>
      <title>STXXL</title>
      <link>https://ihmin.tistory.com/676</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처: &lt;a href=&quot;https://sourceforge.net/projects/stxxl/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://sourceforge.net/projects/stxxl&lt;/a&gt;, &lt;a href=&quot;https://github.com/stxxl/stxxl&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/stxxl/stxxl&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;STXXL&lt;/span&gt;은 외부 메모리 연산, 컨테이너 및 알고리즘을 위한 C++ 표준 템플릿 라이브러리 STL의 구현으로, 디스크를 사용하여 대용량의 데이터를 처리할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 파일을 사용하는 Vector 컨테이너 테스트.&lt;/p&gt;
&lt;pre id=&quot;code_1756785031832&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* $ g++ a.cpp -I./include ./lib/libstxxl_debug.a */

#include &amp;lt;stxxl/io&amp;gt;
#include &amp;lt;stxxl/vector&amp;gt;
#include &amp;lt;stxxl/stream&amp;gt;

using stxxl::file;

int main()
{
	stxxl::syscall_file fd(&quot;c:/temp/a.buf&quot;, file::RDWR | file::CREAT | file::DIRECT);
	stxxl::vector&amp;lt;unsigned int&amp;gt; container(&amp;amp;fd);
	for(int i=0; i&amp;lt;1000; i++) {
		container.push_back(i);
	}

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행결과..&lt;/p&gt;
&lt;pre id=&quot;code_1756785066415&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[ihmin@KC22009 temp]$ ./a.exe
[STXXL-MSG] STXXL v1.4.1 (prerelease/Debug)
[STXXL-ERRMSG] Warning: no config file found.
[STXXL-ERRMSG] Using default disk configuration.
[STXXL-MSG] Disk 'C:\msys2\tmp\stxxl.tmp' is allocated, space: 1000 MiB, I/O implementation: wincall autogrow delete_on_exit queue=0 devid=0
[STXXL-ERRMSG] Removing disk file: C:\msys2\tmp\stxxl.tmp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/3BLEN/dJMb9YiP8qd/FYdvIAsKjkJFNp351wkQKK/stxxl-1.4.1.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;stxxl-1.4.1.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.33MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bjOrDR/dJMb9YwniAn/cjalQrp3PdZgWFUpkCjj9K/stxxl-1.4.1-doxygen.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;stxxl-1.4.1-doxygen.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;6.44MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>블로그 (Blog)/개발로그 (Devlogs)</category>
      <category>container</category>
      <category>File</category>
      <category>stl</category>
      <category>stxxl</category>
      <category>vector</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/676</guid>
      <comments>https://ihmin.tistory.com/676#entry676comment</comments>
      <pubDate>Tue, 2 Sep 2025 12:53:06 +0900</pubDate>
    </item>
    <item>
      <title>tDOM 0.9.6</title>
      <link>https://ihmin.tistory.com/309</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;http://www.tdom.org/index.html/dir?ci=trunk&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://www.tdom.org&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tDOM - a XML / DOM / XPath / XSLT / HTML / JSON implementation for Tcl&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Version 0.9.6&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Added documentation for the scripted additional XPath functions feature. Thanks to Peter Piwowarski for his valuable input.&lt;/li&gt;
&lt;li&gt;Added the dom command method fromScriptContext.&lt;/li&gt;
&lt;li&gt;Updated to expat 2.7.1.&lt;/li&gt;
&lt;li&gt;Added a way to create XML namespaced attributes in *FromScripts.&lt;/li&gt;
&lt;li&gt;Updated to expat 2.7.0.&lt;/li&gt;
&lt;li&gt;Added the &quot;virtual&quot; JSON type BOOLEAN for text nodes. If the text node value is a boolean in the sense of Tcl then the node serialize to the approprate JSON type. Otherwise it will be a JSON string.&lt;/li&gt;
&lt;li&gt;Added the flag -notempty to dom createNodeCmd. If this flag is used the element will only appear in the tree if it is not empty.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Added&amp;nbsp;the&amp;nbsp;dom&amp;nbsp;command&amp;nbsp;method&amp;nbsp;jsonEscape&amp;nbsp;which&amp;nbsp;escapes&amp;nbsp;the&amp;nbsp;string&amp;nbsp;argument&amp;nbsp;for&amp;nbsp;literally&amp;nbsp;use&amp;nbsp;in&amp;nbsp;a&amp;nbsp;JSON&amp;nbsp;string. &lt;br /&gt;Updated&amp;nbsp;to&amp;nbsp;expat&amp;nbsp;2.6.4. &lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;tDOM contains&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;for convenience expat 2.6.2, the XML parser originated from James Clark, although you're able to link tDOM with other expat versions or the library provided by the system.&lt;/li&gt;
&lt;li&gt;building a DOM tree from XML in one go implemented in C for maximum performance and minimum memory usage, and DOM I and II methods to work on such a tree using either a OO-like or a handle syntax.&lt;/li&gt;
&lt;li&gt;a Tcl interface to expat for event-like (SAX-like) XML parsing.&lt;/li&gt;
&lt;li&gt;a complete, compliant and fast XPath implementation in C following the November 99 W3C recommendation for navigating and data extraction.&lt;/li&gt;
&lt;li&gt;a fast XSLT implementation in C following the W3C Recommendation 16 November 1999.&lt;/li&gt;
&lt;li&gt;optional DTD validation.&lt;/li&gt;
&lt;li&gt;a rich and Tcl'ish language to describe structures and text content and to validate XML data or DOM trees or other forms of hierarchically data with that.&lt;/li&gt;
&lt;li&gt;a JSON parser which parses any possible JSON input into a DOM tree without losing information.&lt;/li&gt;
&lt;li&gt;an efficient and Tcl'ish way to create XML and HTML documents and JSON strings.&lt;/li&gt;
&lt;li&gt;as build option an interface to the gumbo HTML5 parser, which also digests almost any other HTML.&lt;/li&gt;
&lt;li&gt;an even faster simple XML parser for trusted XML input.&lt;/li&gt;
&lt;li&gt;a slim Tcl interface to use expat as pull-parser.&lt;/li&gt;
&lt;li&gt;a secure way to share DOM trees by threads&lt;/li&gt;
&lt;li&gt;additional convenience methods.&lt;/li&gt;
&lt;li&gt;and&amp;nbsp;more.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/b7QIot/dJMb9PsGd9T/jgk9X454mO5jeo8emOzGV1/tdom-0.9.6-src.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tdom-0.9.6-src.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.46MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/5MGGl/dJMb9P0v8AZ/3lKOdaYCgVpka3KjKUto41/tdom-0.9.6-windows-32.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tdom-0.9.6-windows-32.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.59MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/IboD2/dJMb9XjVNA0/ksd9g7O7iilCSeuSduFYc1/tdom-0.9.6-windows-64.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tdom-0.9.6-windows-64.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;1.55MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <category>tdom</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/309</guid>
      <comments>https://ihmin.tistory.com/309#entry309comment</comments>
      <pubDate>Tue, 2 Sep 2025 10:55:38 +0900</pubDate>
    </item>
    <item>
      <title>Tclcsv 2.4.3</title>
      <link>https://ihmin.tistory.com/675</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지: &lt;a href=&quot;https://sourceforge.net/projects/tclcsv/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://sourceforge.net/projects/tclcsv&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tclcsv는 CSV 포맷의 파일을 읽고 쓰기 위한 바이너리 확장 패키지입니다. 또한&amp;nbsp;CSV&amp;nbsp;형식을&amp;nbsp;설정할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;Tk&amp;nbsp;위젯도&amp;nbsp;포함하고&amp;nbsp;있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tclcsv&amp;nbsp;is&amp;nbsp;a&amp;nbsp;binary&amp;nbsp;extension&amp;nbsp;for&amp;nbsp;reading&amp;nbsp;and&amp;nbsp;writing&amp;nbsp;CSV&amp;nbsp;format&amp;nbsp;files.&amp;nbsp;It&amp;nbsp;also&amp;nbsp;includes&amp;nbsp;a&amp;nbsp;Tk&amp;nbsp;widget&amp;nbsp;for&amp;nbsp;configuring&amp;nbsp;CSV&amp;nbsp;formats.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biarg3/btsQgs6A7xF/JGY96lOiCrrvBFk9ntMLG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biarg3/btsQgs6A7xF/JGY96lOiCrrvBFk9ntMLG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biarg3/btsQgs6A7xF/JGY96lOiCrrvBFk9ntMLG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbiarg3%2FbtsQgs6A7xF%2FJGY96lOiCrrvBFk9ntMLG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;536&quot; height=&quot;566&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;566&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/btIAic/dJMb9Lw2X5K/6bXQDAOqNZckkWKl2B4grK/tclcsv2.4.3-src.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tclcsv2.4.3-src.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.20MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/675</guid>
      <comments>https://ihmin.tistory.com/675#entry675comment</comments>
      <pubDate>Tue, 2 Sep 2025 10:37:22 +0900</pubDate>
    </item>
    <item>
      <title>Tablelist 7.7</title>
      <link>https://ihmin.tistory.com/340</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈페이지&amp;nbsp;:&amp;nbsp;&lt;a href=&quot;http://www.nemethi.de/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://www.nemethi.de/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N9TmE/btsJr0uV78p/p2u6pVIVCn1PKbubKrykxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N9TmE/btsJr0uV78p/p2u6pVIVCn1PKbubKrykxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N9TmE/btsJr0uV78p/p2u6pVIVCn1PKbubKrykxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN9TmE%2FbtsJr0uV78p%2Fp2u6pVIVCn1PKbubKrykxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;843&quot; height=&quot;411&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;What&amp;nbsp;Is&amp;nbsp;Tablelist?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tablelist is a library package for Tcl/Tk versions 8.4 or higher, written in pure Tcl/Tk code.&amp;nbsp;&amp;nbsp;It contains:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;the&amp;nbsp;implementation&amp;nbsp;of&amp;nbsp;the&amp;nbsp;tablelist&amp;nbsp;mega-widget,&amp;nbsp;including&amp;nbsp;a&amp;nbsp;general&amp;nbsp;utility&amp;nbsp;module&amp;nbsp;for&amp;nbsp;mega-widgets;&lt;/li&gt;
&lt;li&gt;a demo script containing a useful procedure that displays the configuration options of an arbitrary widget in a tablelist and enables you to edit their values interactively;&lt;/li&gt;
&lt;li&gt;a demo script implementing a widget browser based on a tablelist used as multi-column listbox;&lt;/li&gt;
&lt;li&gt;a demo script implementing a widget browser based on a tablelist used as multi-column tree widget;&lt;/li&gt;
&lt;li&gt;a demo script implementing a directory viewer based on a tablelist used as multi-column tree widget;&lt;/li&gt;
&lt;li&gt;a demo script showing several ways to improve the appearance of a tablelist widget;&lt;/li&gt;
&lt;li&gt;four further demo scripts, illustrating the interactive cell editing with the aid of various widgets from the Tk core and from the packages tile, BWidget, Iwidgets, combobox (by Bryan Oakley), and Mentry;&lt;/li&gt;
&lt;li&gt;one further demo script, with a tablelist widget containing embedded windows;&lt;/li&gt;
&lt;li&gt;tile-based counterparts of the above-mentioned demo scripts;&lt;/li&gt;
&lt;li&gt;this tutorial;&lt;/li&gt;
&lt;li&gt;reference&amp;nbsp;pages&amp;nbsp;in&amp;nbsp;HTML&amp;nbsp;format.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tablelist는 여러 열(컬럼)로 구성된 list box 및 트리 위젯입니다.&amp;nbsp;&amp;nbsp;각 열의 너비는 동적(즉, 헤더를 포함한 모든 요소를 담을 수 있을 만큼만 큰 크기)이거나 정적(문자 또는 픽셀 단위로 지정)일 수 있습니다.&amp;nbsp;&amp;nbsp;열은 기본적으로 크기를 조정할 수 있습니다.&amp;nbsp;&amp;nbsp;각 열의 정렬은 왼쪽, 오른쪽 또는 가운데로 지정할 수 있습니다. &lt;br /&gt;&lt;br /&gt;열, 행 및 셀은 개별적으로 구성할 수 있습니다.&amp;nbsp;&amp;nbsp;전역 및 열별 옵션 중 일부는 라벨 위젯으로 구현된 헤더 타이틀들을 참조합니다.&amp;nbsp;&amp;nbsp;예를 들어, -labelcommand 옵션은 머리글 레이블 위에 마우스 버튼 1을 놓을 때 호출할 Tcl 명령을 지정합니다.&amp;nbsp;&amp;nbsp;이 옵션의 가장 일반적인 값은 각 열을 기준으로 항목을 정렬합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tablelist 패키지는 들여쓰기 및 확장/축소 컨트롤을 사용하여 트리 계층 구조를 표시하는 열의 모양과 느낌을 제어하는 매우 다양한 트리 스타일을 제공합니다. &lt;br /&gt;&lt;br /&gt;tablelist 위젯의 요소를 개별 셀과 전체 열에 대해 대화형 편집을 활성화할 수 있습니다.&amp;nbsp;&amp;nbsp;내장된 편집 창으로 사용할 수 있도록 Tk 코어 및 타일, BWidget, Iwidgets, combobox, ctext, Mentry(또는 Mentry_tile) 패키지에서 제공하는 다양한 위젯이 지원됩니다.&amp;nbsp;&amp;nbsp;또한 편집 가능한 셀 사이를 편안하게 탐색할 수 있도록 다양한 키보드 바인딩 세트가 제공됩니다. &lt;br /&gt;&lt;br /&gt;tablelist 위젯에 해당하는 Tcl 명령은 일반 listbox에 연결된 명령과 매우 유사합니다.&amp;nbsp;&amp;nbsp;configure 및 cget 하위 명령에는 열, 행 및 셀별 대응 명령이 있습니다(columnconfigure, rowconfigure, cellconfigure, ...).&amp;nbsp;&amp;nbsp;특히 셀과 헤더 레이블에 이미지와 임베디드 창을 삽입하는 데 사용할 수 있습니다.&amp;nbsp; index, nearest, see 명령 옵션은 행을 참조하지만 열과 셀에 대해서도 유사한 하위 명령이 제공됩니다(columnindex, cellindex, ...).&amp;nbsp;&amp;nbsp;항목은 &amp;nbsp;sort, sortbycolumn, sortbycolumnlist 명령 옵션을 사용하여 정렬할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tablelist 위젯의 본문에 정의된 바인딩을 사용하면 일반 listbox처럼 작동합니다.&amp;nbsp;&amp;nbsp;여기에는 가상 이벤트 &amp;lt;&amp;lt;ListboxSelect&amp;gt;&amp;gt;(&amp;lt;&amp;lt;TablelistSelect&amp;gt;&amp;gt;와 동일)에 대한 지원이 포함됩니다.&amp;nbsp;&amp;nbsp;또한 위젯 콜백 패키지 Wcb 2.3 이상 버전(순수 Tcl/Tk 코드로도 작성)을 사용하여 활성화, 선택 세트 및 선택 지우기 명령에 대한 콜백을 정의할 수 있으며, Wcb 3.0 이상 버전은 활성화 셀, 셀 선택 세트 및 셀 선택 지우기 명령에 대한 콜백도 지원합니다.&amp;nbsp;&amp;nbsp;Wcb의 다운로드 위치는 다음과 같습니다. (&lt;a href=&quot;https://www.nemethi.de/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.nemethi.de/&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egproe/btsJsJ0pNSR/e4ytECsi5TXY1uwkAuQf3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egproe/btsJsJ0pNSR/e4ytECsi5TXY1uwkAuQf3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egproe/btsJsJ0pNSR/e4ytECsi5TXY1uwkAuQf3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fegproe%2FbtsJsJ0pNSR%2Fe4ytECsi5TXY1uwkAuQf3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;867&quot; height=&quot;413&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi60kF/btsJrrzVRRL/Fhg6XvgcbBYW3K79Jgq5jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi60kF/btsJrrzVRRL/Fhg6XvgcbBYW3K79Jgq5jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi60kF/btsJrrzVRRL/Fhg6XvgcbBYW3K79Jgq5jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi60kF%2FbtsJrrzVRRL%2FFhg6XvgcbBYW3K79Jgq5jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;394&quot; height=&quot;330&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;465&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FwZ1K/btsJsg5mzj2/LhvnbATcfKqGKqGpC16OJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FwZ1K/btsJsg5mzj2/LhvnbATcfKqGKqGpC16OJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FwZ1K/btsJsg5mzj2/LhvnbATcfKqGKqGpC16OJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFwZ1K%2FbtsJsg5mzj2%2FLhvnbATcfKqGKqGpC16OJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;683&quot; height=&quot;465&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;465&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;What is new in Tablelist 7.7?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Added mouse and keyboard event bindings that invoke the &quot;expand&quot; and &quot;collapse&quot; subcommands with the &quot;-fully&quot; option.&amp;nbsp;&amp;nbsp;See the updated subsection &quot;TREE WIDGET BINDINGS:&quot; in the reference manual for details (thanks to Torsten Berg for his proposal and testing).&lt;/li&gt;
&lt;li&gt;Added explicit support for the &quot;droid&quot; theme, which is the default in AndroWish.&lt;/li&gt;
&lt;li&gt;Improvements related to the themes provided by the awthemes package and the ones that are not explicitly supported by Tablelist.&lt;/li&gt;
&lt;li&gt;Improved the interactive cell editing with the aid of the toggleswitch widget.&lt;/li&gt;
&lt;li&gt;The demo scripts &quot;dirViewer.tcl&quot; and &quot;dirViewer_tile.tcl&quot; now work around the fact that on Android the directory &quot;/&quot; is normally not&amp;nbsp;readable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/cDHV1r/btsJql8mJr1/1CEj0ERHXjWl3YGXfYfDn1/tablelist7.3.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tablelist7.3.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.83MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/wqC74/dJMb9NIoJPs/RCt1Fmz4nxmjBFsJ5vuo8K/tablelist7.7.tar.gz?attach=1&amp;amp;knm=tfile.gz&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tablelist7.7.tar.gz&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.89MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tcl &amp;amp; Tk/확장 패키지 (Extension Package)</category>
      <author>티클러</author>
      <guid isPermaLink="true">https://ihmin.tistory.com/340</guid>
      <comments>https://ihmin.tistory.com/340#entry340comment</comments>
      <pubDate>Tue, 2 Sep 2025 10:30:24 +0900</pubDate>
    </item>
  </channel>
</rss>