From 83c2c367814da0367f1a4db84655d7f7ac5dbeb0 Mon Sep 17 00:00:00 2001 From: zhukovskaia Date: Mon, 9 Mar 2026 10:38:21 +0500 Subject: [PATCH 1/6] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=D0=B0=20=D0=BC=D0=B5=D0=BD=D1=8E=20=D0=A4=D0=B0=D0=B9=D0=BB=20?= =?UTF-8?q?=D0=B8=20=D0=BF=D0=BE=D0=B4=D1=82=D0=B2=D0=B5=D1=80=D0=B6=D0=B4?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D1=8B=D1=85=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 3 + .idea/Robots.iml | 12 +++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ out/production/Robots/.classpath | 6 ++ out/production/Robots/.gitignore | 2 + out/production/Robots/.project | 17 ++++ .../Robots/gui/GameVisualizer$1.class | Bin 0 -> 575 bytes .../Robots/gui/GameVisualizer$2.class | Bin 0 -> 580 bytes .../Robots/gui/GameVisualizer$3.class | Bin 0 -> 803 bytes .../Robots/gui/GameVisualizer.class | Bin 0 -> 5627 bytes out/production/Robots/gui/GameWindow.class | Bin 0 -> 856 bytes out/production/Robots/gui/LogWindow.class | Bin 0 -> 2580 bytes .../Robots/gui/MainApplicationFrame.class | Bin 0 -> 6128 bytes out/production/Robots/gui/RobotsProgram.class | Bin 0 -> 1542 bytes .../Robots/log/LogChangeListener.class | Bin 0 -> 148 bytes out/production/Robots/log/LogEntry.class | Bin 0 -> 651 bytes out/production/Robots/log/LogLevel.class | Bin 0 -> 1341 bytes .../Robots/log/LogWindowSource.class | Bin 0 -> 2507 bytes out/production/Robots/log/Logger.class | Bin 0 -> 858 bytes robots/src/gui/GameVisualizer.java | 16 ++-- robots/src/gui/GameWindow.java | 2 +- robots/src/gui/LogWindow.java | 41 +++++---- robots/src/gui/MainApplicationFrame.java | 79 +++++++++++------- 25 files changed, 142 insertions(+), 56 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/Robots.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 out/production/Robots/.classpath create mode 100644 out/production/Robots/.gitignore create mode 100644 out/production/Robots/.project create mode 100644 out/production/Robots/gui/GameVisualizer$1.class create mode 100644 out/production/Robots/gui/GameVisualizer$2.class create mode 100644 out/production/Robots/gui/GameVisualizer$3.class create mode 100644 out/production/Robots/gui/GameVisualizer.class create mode 100644 out/production/Robots/gui/GameWindow.class create mode 100644 out/production/Robots/gui/LogWindow.class create mode 100644 out/production/Robots/gui/MainApplicationFrame.class create mode 100644 out/production/Robots/gui/RobotsProgram.class create mode 100644 out/production/Robots/log/LogChangeListener.class create mode 100644 out/production/Robots/log/LogEntry.class create mode 100644 out/production/Robots/log/LogLevel.class create mode 100644 out/production/Robots/log/LogWindowSource.class create mode 100644 out/production/Robots/log/Logger.class diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/Robots.iml b/.idea/Robots.iml new file mode 100644 index 0000000..d58e90e --- /dev/null +++ b/.idea/Robots.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..fbd542f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..650a132 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/out/production/Robots/.classpath b/out/production/Robots/.classpath new file mode 100644 index 0000000..fceb480 --- /dev/null +++ b/out/production/Robots/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/out/production/Robots/.gitignore b/out/production/Robots/.gitignore new file mode 100644 index 0000000..2757ffa --- /dev/null +++ b/out/production/Robots/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/.settings/ diff --git a/out/production/Robots/.project b/out/production/Robots/.project new file mode 100644 index 0000000..78e1656 --- /dev/null +++ b/out/production/Robots/.project @@ -0,0 +1,17 @@ + + + Robots + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/out/production/Robots/gui/GameVisualizer$1.class b/out/production/Robots/gui/GameVisualizer$1.class new file mode 100644 index 0000000000000000000000000000000000000000..f1c0ca4485b43db7ec3ff2526522fded4fa46813 GIT binary patch literal 575 zcmZvZOHaZ;5Xb+Em6lQ-g5ukFAQ8}rUc8`Q2tE?@poaSj8(l5iq}yWRw=(gOc<=-G zp^USY#2DFRcXp=#`OWO~^XvTszya1WNMXu`4@l`rPmFP#S+6 zw9H!=Didhc-4^v1#)`qc4C1gaj-=s~|4wAvJdo;jRNoJ@R5xcLx(x;l&biRhNua4) z?^G!fwtcR(&{(G_J2Y@sESfpfEk!$v5(rMWL-I|;ZEU`PHQr!9C7M|})1(15Fh^(Q zM@4p?JklpLMv4V^W7Zy7li@U;!CsO3CAmrVCTwgaG?PKPG0nmvc_}PmnXE;BD1((G NlE*4pm(-?5THil}aOeO4 literal 0 HcmV?d00001 diff --git a/out/production/Robots/gui/GameVisualizer$2.class b/out/production/Robots/gui/GameVisualizer$2.class new file mode 100644 index 0000000000000000000000000000000000000000..342880fb9930a99e0a5e8fc390d5bc4756ea5249 GIT binary patch literal 580 zcmZvZ%TB^T6o&u7N}*IiK=2+HEC3TRXxyM|3|izurFp9AYDl1ZHelE@qKrC|*ahal*%9Aa%q&`6z-)lOY-2 zNL|^X@7-xb%Rvfh8;*+%T!z9ef8dQMlwRXPjzw_6^&KG&q>^EqVWwIeIG9J)M$W~8 zsmM=5N%U3E9|`aBe#Ar3c@QdOC|Cb$pf+Hzj>ycA?Mfy3(fG=od*zXm@A^aT4R|0; zJ`pW*A%@aFv`Vu@O$L!-aL)ZG7>Z+QIEBAs**3SN^Ezti`C6*$o(OOJ5ksmkba?7( z>ef9|N(4t9*IH<7(x_83b(YJSVbd-_Zw7e~oOW%>jpEd|Ucl;au%BX2k=7)6fCd(6 zE&aGCmMJ5DOk?C&f;(aDQ#2K+`ZL%o=6*>|T)hh$doj&akZ(e>uuNG3D_Esy(Qis) PEmr2SPSGK^>5-mqH&Sx; literal 0 HcmV?d00001 diff --git a/out/production/Robots/gui/GameVisualizer$3.class b/out/production/Robots/gui/GameVisualizer$3.class new file mode 100644 index 0000000000000000000000000000000000000000..0892b40354895aaa6866a51ed921f43e7702fd18 GIT binary patch literal 803 zcmZuvZEq4m5Pk+u4z6cQIiyy!zM&qFh)F;Af!f57`jXJr#D?!%*wEGEuDM-m;=eLc zO#I*v@JAVEPg1II$?eX}KKslwv-9iskDmZupj|=^c^8h4YbX$^BtKio6cb})$-*?oEw=k)t-u# z*(c<~=D@=`He8f_Y@$NgUUl=pk`RhxY2GEunw7BGzeHv+mQckF7d0PSxXFlRm4r<# z&51}e9<7W@VnPu9&tyeaamz>D*5an}Tx3bN!d0a=2Lz{=j3i;BuVQ&Lot(<_M4Uz( zsq~Yfhz256)}IF*+e$)h1zTgcOYkSQUA;&RKgtnd=Ze59?aZ3ewb_Xi)fYu9VF=#) zWSS1;D`hnW|3294hMDo}^Pj{c}|Ihz_=ldQ1 zKY9AC`yT>ul2WUpL_yUD^-;YwYsC|-eetA`_QR{7+88xbR_5rKkuuV{Wu^mA;M1VO z&+)`~DsC-TFukeUW=`m-SnF0R9Z$vDPjBuIAb@fenvhp0s1cf-t(hI%Zr!k1PZz>ex=v3T{qamzPsGnP(hAB%m2H=T+NNelU%}Y+GRmmaFdZ`# zsL5@Xc%Wd~5p=$l1N506VVJGqD9oXk$!%$K(6lz2nYa}Q6VI)z}ahNGt<7?92R z8s1a9*%?n85n-3j1sWQ$kQUGuJsmS9$?g)0W)0yfDF#$5QV={6g@$7SXu%SJvsJ;2 zrtTw2+MD}J9sjUYLUpW$6~OD$GsEp0HZ=FEc>mOjDQg*) zrJWiNte-hLu=FX!U5c$INDo?s&$MBvLTXH9+5Cwc6>`I*EWTh=2|a zomfKvGltb^W(O0->g>>vkv5_VyiLrmGOWXT628zthW;|svf;)wxTSJd* zD`PdpW7<5Xr~UfCL{k1bgvOJvLA zsZn#-=+-T9lkq7OMP86NH-OVsoT1?ZI5TIrT{%6vwVlpo&PmgJZ&PP;r_gTGa5i)W zrMji3mU3+Bw0Eiy(GV38wR&cgnNHfJ67AKaaXpn02!}MpK#Be+vDZ@(ny8Xl*nKNr zani)M;=UW@vquJlON{t9uXo9?nfxHaL7jzC*)KjIlP8=BUvt z1;m~p3Y-X@r{P05pRnj7BZ;x@crtEfas;+#7izdj?Du5isQ@m)r7AwG;WB)LX;XmC z2|m4uXVyv+pcjJ8>4MGW8m_PFgTNWY_LeTVD!?4qPD zh-vTYa>2Ms!_D}Vf`IV!*&U%!ip5qf?Ie=`_-TAb#b-5q4!5!j@(Gs{PC$m@iNwjH zI=iUa)Wwg(^#u)I6c)c|lI;M#guNT78@s!b*X3h*TiKvRr zs@Jrb#9gUe+BDcvb@Ew^or;q+at*$$VIS^Rps{L;WX>-_XG&fv=X>xK758d5fbm>e zh^`JZVX~amo>lACZ0eJiQn16`vlUNhxDWT!Ybtg*YKxRQgic;QAecTlHTuL}a1>)6 z*6@f}Qo6c(RmVn&`(uLagR=L8hOgRtr>^hnTO%t^Y51DGvaWZ{noUglq`tG?NSKkh z#R{qDFl{WYemxhjJ9Vr?g8seF0j{_Ws(q>YgW#qHRGWo<`&TGt658X_hG7@EmxkCM;1*F{8 zlPi%bK2L_JVymS`hI{mp91u)#!PJwCv!{EAtmJ-{w-p}6>=h|v2er#U^%{r#IZX>~ zZFD|HSPH1*YOI~|VoO>2bw}>8PMMSuc7G#H`R+`-Xa7wSAA2M^WzpQdfa>jQMn{gR z_>r6n`{&$(rYQ@B9b~JSO-GEiaY>EZ$@iosQrk?vO-9D*F(ieU8r7>!)5=)vdOe1< z-Hc|ce3YUnN{Om?G{viwDwtpBx6UEf+N~!CqdGbCAw9y2-q_xL(~;0K86%@ARSFgy0pnDNsLC`2 z_3uu~gVKQy^VoR;JaqlM9rJq2*=o79+9NNg_Q-pvJ@U$FkGxoNoQ1D*UBT0wmtdIB z&lEk6pqg@d<0i$kq-ckiGoa!Slz|$L_aI6)hVQmnpW|jbnM(JC4=+^X4t3LBIm~P(!n3@pm?65~q587ho>$ z&5c-&CD_7??3q}BL0(UDZU7Oyh?mIk#mo4H>qZZq6PKrjTkgeLv6SOR+FDRr2@eT6 z8JaZ&bFD3Ky2IoOBs;!|Z&9Qd-_9d+Jf8*XK=^)a0w&N~km=yOf$t|9iwq37@&a8$;e$o4+aKi?szp{*Zq-6bJ=|BNI4nAGb>&;d4wqnJk;hw8a*^oKIxO zckJwu*>^b;pJ(HHoO$ip_c`(E(rIl@JsFZ8-cHaVj z5F@!q^6@dBlXy614;Uq?F9pdO_5%wdA zGcdxPb8O#_gS=J^x$&LO@Wkk+Lf#Jij57}d>7giGC37osWnUE1gPHnsw zHk$%%bEs4@^a7c4hz&=GvO0l__h35LW-a8tv$spOIIW+|DN!ZouGny_tt?cQ=d3Sq zUO>*Wa7dNL6Dm7^dSP)D54M$uL*;Bkg$S-?W&sy4doHAt7oh4Rx-?5V-QzH z*4_5@>oVDWld}-x!fQta{dxxd1_pc&>*{9ykK-2GYU$~ehCfm>Y|W)igGxCk_$K5k zJ;qh4QcFB?^_`@2T8z{6Z!MCfy6L0X7&*tx`P3}lw}x8|;;NQMa7|Bm5d$-80@q2D zonhWMuD6#PxYjg|J%tA8WbIx8cRTI6gXiO&?CWI7_E!7}f2Q35o&kTst28tq zcYoKDIAuuj)rM!!DNRI=s`K)9P8|=HTMFu&e!QQBagVLSsn=RtFnM`=zQ)5=aI3{% zIg@zQ;&sl%%Ub-6GcVQh&EdbQ{ro%Cj#KTy|3htwyr?>Al^}ta#%Q@8TJFLAaU5)^^VO-<_0@q19OBYLlb0Ul(&Nrjb>Qqe)z5BU zM3!HBwBXk=yE`1BB@fWI2iYbcVr(8}i+cpe<58Z>kMZDp9KCn~+xU_-geQ@~Q#J;@ z>{7HpA6<(avB$JF3!8KIPb#ZybFt67yJZ9jP&yRCe13rVf>q;pYFBu8qpF literal 0 HcmV?d00001 diff --git a/out/production/Robots/gui/GameWindow.class b/out/production/Robots/gui/GameWindow.class new file mode 100644 index 0000000000000000000000000000000000000000..ecd8e5c3f3e21fb9bb91d59ba1cb775cd79e4927 GIT binary patch literal 856 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 literal 0 HcmV?d00001 diff --git a/out/production/Robots/gui/RobotsProgram.class b/out/production/Robots/gui/RobotsProgram.class new file mode 100644 index 0000000000000000000000000000000000000000..04382b3dec85dbbb562b64b12be38eb162bd79cf GIT binary patch literal 1542 zcma)6U31e$6g_J@mLnAGIE@q1HjofXY+4KGcgFJaNG0_xhU{u}zkmWm)g&F&Y>jM>Pq(8gSftvOkNNiuBq;( z5WWo?XDm1lrf`;FHUYW`(0#n!aH+nZC z-WN6&ku}4zgNsIaE+ow+aLK_pxXfUaE&DQ-q>ffspBTm}xs^D;Uut*EbH%~8_>Q)Z z5F1BYsIKUe1vaQc}^AO6&~!Z4vDmGZ@NV(Bb|* zkED4Y1#|kDr0!?DPna4+)u$$nyH8W@j`xm%5$kMfX}o&|%cGtlJ_X7!m275{ha(kJ zKJT}?e8tpTxymqcVCCwX@_AZK*M!=}*Bf^J;Q zW8KE@*s!qa;2yRZmQN1f@C3MCqJPrv<_J{%*^u)r2qU0=j2=Hw5; zM#`FzYpKXbz`a+YNT>h*#bL?MW78kUhjd79KGyem<2hpP@NeqKX;%l7TE}$C0P;D!sWhGnyxAZ@^yDpA4?i zXqJHjuG8oY6YxELptni9PuM)3wc7BX8Fin)?)Y#RyKC4dn+ z|2G!@e1i-3YsXls<&LpZE9H+-J87swMM1&}RLopv)0m^*{J23Q=O%7ZP8PRm%-{~z YXg1B?rPwz9pr=U@n<6`Sh+Ulf04ywh%>V!Z literal 0 HcmV?d00001 diff --git a/out/production/Robots/log/LogChangeListener.class b/out/production/Robots/log/LogChangeListener.class new file mode 100644 index 0000000000000000000000000000000000000000..7788a76dcc82402829e0144685c8bb3ed8c7996d GIT binary patch literal 148 zcmX^0Z`VEs1_oOOPId++Mh4NG{B(Vv{B-Ax#Ju!WpUmQt)V$Opb_Nzk27#=^vPAtH zpt!z&QdVkm2_pkfejZ$H3L^uvhGrNe16Ocb|A^bzySb6Z6o>s literal 0 HcmV?d00001 diff --git a/out/production/Robots/log/LogEntry.class b/out/production/Robots/log/LogEntry.class new file mode 100644 index 0000000000000000000000000000000000000000..6dbb11497b76d2a822f5e5064660ad55c259a303 GIT binary patch literal 651 zcmZuu%TB^j5IwgP3Z+0r@coP%sK$N(>c;4*>H7@|_(_~(qbI#1%ukVjf0O#0OAt9qc){sSxK_A#-+w^STG4FZ<-j5k_XRhzY7Yvz3 zvr|AG1qG^xA~Xig3mnr5oGU*LpD7)7qd2_bQDi%up=!<8+HvUmPAkEeHB_K8sKYM7 zEk5QRL)l8HMBZXJYW%G%b2U2*@@4QyN)^lX`R!=f+NQ)8sBVq+3Yz z3KD&E5E0Q;$!EamIabJ4DSJqshkaVO0NR2O127_Y=Nvwwumy3)TnYW zg`ti$%7_5#B*R3sK|K=1o7hTaO!CRUtnmirg#rl)c}^5{L8wg|QbLAp>`*0{aUNV+ M1lRus?+S^%A7Mmzf&c&j literal 0 HcmV?d00001 diff --git a/out/production/Robots/log/LogLevel.class b/out/production/Robots/log/LogLevel.class new file mode 100644 index 0000000000000000000000000000000000000000..cea0168ac7bcbc95579ec49bb65da83bb93ea19c GIT binary patch literal 1341 zcmZuw+fvg|6kVseHUuc;CKnL_wJl0T!CMhgE?Vu#LlCFKgA;0~VbXLawETp>;)50y zMn}hIKgx0M(=xU~9uqUOWBDhGOO^m4#>?M9&=N>HDTq@=A!Q8i-J zfQ>;J*>G#FtUhex0!D~8v;Da6YTXg&-RW$=!WhO4jM%t{32L(xR6}ZWAeAocyN7Nz zaKmzTb9dh>)p8alaoNC>jcLqKQ~v<#VZB0C4&9*cZSDyyrrOx6fqQU}YYRBFh-S#O zSKtIP|5Y2;kP^_B{Lrs03kCNzuAvYh9p!0>r= z;+u$@uub%uNSYXA%3T}xaG%AJa~uftrPBY&MU9;vs;kwvq*QOg551T5%B~k}xw`>H zrp_su?o?eMS*VuWVB3v+CbgJq=vF8}@~l?03$=GXwWOa;8h8A1=+^2H5!4h-M3)!v z)(I%7be>dMDg`YKDL}`QZE0EWrOuv~a{`uAtw$wq!{<4=Pxp9^FM4I3B$}jEH&;e@ zr2(?Ex6;zKN=r*BEiI#!b>cn1eae?3Z;C8GRs%y{G5QN*AITF~ zqPH&36v9u_FV@5_P(Ef@Ns&3hrC$(?k9FXeDPlKKc!U*sPU}D@uJ{ZJR7PZG$B%I( zbMXt(pCpEB_RuN#cS8bQ=mX~(A|_{iEa%~`Cp3|QRf@*2MwQmF(dsWtmiyB(pOO9` z0slrBl~wLW&{1s zS+Pt!r4gHAy{D_0$jO3#qqElrc2CB56aF1>E)Ef|LM64F~V uP3iTY;LZ_-Sh?nHO~9aUjTF=|PTv`rG+LaLv9LvI#aeph@tklmy!Z>;fvxcaS7U%+SuPs|vn@7yGI^uHPL;PzYL_()i58@BQpY=zY~8WRT{Wa-Y5KH|QJf(WW$SD5NW!yG zoW+=ijE-@fBdl!>CY@rD0Y^<)DHj5>~2$W38Sj|^ewk*xE=T22?Q|4itP+!Jm)0EY3 zLawYT*4Z}63Tc*kkwBTY=CWtF-euP*(Q@9Y*wlo^u4CSvbz}w9)$!WJUDyv8#iGFe znnqtcPCv(Y-PpxWwA$@1TT%%7SVxUK56gTY!M4)GHXG!V?UJ)5+1DU&Ma{G5kUgvZ z{voS_J&1c6*Vq#I{D^O+vH&E~TM+5^2DJ1Ov@XQA(6)gNHQ&Pi4Rk+LW^;V*=XIcm z7h`C~0Xm7(^g&FiJqap-XD)YY7Af-K_7RIpdCkv;1~|G6K*5ut0U;c3})&1Q(Eak z(<_?cHz}eatFF!vYH2z>T$_>TNnd@14^AihE38zR2p|AlV>scQa2hIpG9&H5Ac zFANNB;jL+=uwzK2@DX~)g0bKWjH>L8g=BhrUmzx51HT}>iNRlSVl0@B1)1$wi0N(_ z3v-NxpT&Y>p;+kYXgDycb!lDUd+3gZy0nvHkyzv>ye;sJChoubLlSeGO*BgoSteSJ zRbocjUxAZ|@*~iRQxwQ)^x_OppJfU%{82EDNlZ`-=W&~gbUEI|MU|Kdgt?|Ex*{^X zI)&@FjvEYKu6>R#=sgMtUt*D7W4Ot`1XCgj?nCG$CN=bHI6-tAsKim3gXd;x5kxgR~x7N78Hp} zAn^fw6k^tPfYRUxd(U{!oSE7E@$>6<0FSX_p@OOj!$u8r0_{Wp#P7v^682sX59KHm znA?q#D0?DMb=*M%bu>&^Hkz;ntT+vOUK)l{u{V$h{v^&=@23+rk^&vC-0(I^g7iZH z_Zw(o!9?4}B9;W~a*roZWGqnIlfy|U(3zV)f;~p z6It@oksl9y73sPJjqH6irlaX_=F%s5P&n#1vt%&Eai(6%@z@V@-V0L6AhkTY4rR7? zA>}p4oen&gvp{`!6ql!G72!XRwD=~^h}w4aC_LbqR(Kl(*7d1!Rb$QTK;$~Bhx`hS zcF!O_aZ$kyzV*!k8w|GG { + System.out.println("Выход из приложения"); + exitApplication(); + }); + + fileMenu.add(exitMenuItem); + + JMenu lookAndFeelMenu = new JMenu("Режим отображения"); lookAndFeelMenu.setMnemonic(KeyEvent.VK_V); lookAndFeelMenu.getAccessibleContext().setAccessibleDescription( @@ -110,7 +129,7 @@ private JMenuBar generateMenuBar() setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); this.invalidate(); }); - lookAndFeelMenu.add(systemLookAndFeel); + lookAndFeelMenu.add(systemLookAndFeel); // this.invalidate() - помечает контейнер как требующий перерисовки } { @@ -124,7 +143,7 @@ private JMenuBar generateMenuBar() JMenu testMenu = new JMenu("Тесты"); testMenu.setMnemonic(KeyEvent.VK_T); - testMenu.getAccessibleContext().setAccessibleDescription( + testMenu.getAccessibleContext().setAccessibleDescription(//всплывающая подсказка "Тестовые команды"); { @@ -135,19 +154,21 @@ private JMenuBar generateMenuBar() testMenu.add(addLogMessageItem); } + menuBar.add(fileMenu); menuBar.add(lookAndFeelMenu); menuBar.add(testMenu); return menuBar; } - private void setLookAndFeel(String className) + private void setLookAndFeel(String className)//смена оформления { try { - UIManager.setLookAndFeel(className); - SwingUtilities.updateComponentTreeUI(this); + UIManager.setLookAndFeel(className);//меняет тему + SwingUtilities.updateComponentTreeUI(this);// updateComponentTreeUI - рекурсивно обновляет все компоненты + // this - текущее окно (MainApplicationFrame) } - catch (ClassNotFoundException | InstantiationException + catch (ClassNotFoundException | InstantiationException // Перехват возможных исключений при смене темы | IllegalAccessException | UnsupportedLookAndFeelException e) { // just ignore From 5ebe21230e9a6d91aab87acf57855e9fa1c19252 Mon Sep 17 00:00:00 2001 From: zhukovskaia Date: Fri, 17 Apr 2026 13:08:08 +0500 Subject: [PATCH 2/6] =?UTF-8?q?task-02:=20=D1=81=D0=BE=D1=85=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=20=D0=B2=D0=BE=D1=81?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=B3=D0=B5=D0=BE=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=BE=D0=BA=D0=BE=D0=BD=20=D0=BF=D1=80=D0=B8=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=83=D1=81=D0=BA=D0=B5/=D0=B2=D1=8B=D1=85=D0=BE=D0=B4?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robots/src/gui/MainApplicationFrame.java | 231 +++++++++-------------- robots/src/gui/RobotsProgram.java | 32 ++-- robots/src/gui/WindowConfigManager.java | 64 +++++++ 3 files changed, 161 insertions(+), 166 deletions(-) create mode 100644 robots/src/gui/WindowConfigManager.java diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index 6186176..6e8fd6f 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -1,93 +1,88 @@ package gui; -import java.awt.Dimension;//размер -import java.awt.Toolkit;//инфа об экране -import java.awt.event.KeyEvent; - +import java.awt.Dimension; +import java.awt.Toolkit; +import java.beans.PropertyVetoException; import javax.swing.*; - import log.Logger; -/** - * Что требуется сделать: - * 1. Метод создания меню перегружен функционалом и трудно читается. - * Следует разделить его на серию более простых методов (или вообще выделить отдельный класс). - * - */ -public class MainApplicationFrame extends JFrame -{ - private final JDesktopPane desktopPane = new JDesktopPane();//рабочий стол - +public class MainApplicationFrame extends JFrame { + private final JDesktopPane desktopPane = new JDesktopPane(); + private LogWindow logWindow; + private GameWindow gameWindow; + private final WindowConfigManager config = new WindowConfigManager(); + public MainApplicationFrame() { - //Make the big window be indented 50 pixels from each edge - //of the screen. - int inset = 50; // отступ - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();// через сист настройки получаем доступ к окну - setBounds(inset, inset, - screenSize.width - inset*2, - screenSize.height - inset*2); - - setContentPane(desktopPane);// заменяет основную панель окна на нашу - - - LogWindow logWindow = createLogWindow(); - addWindow(logWindow);// на рабочий стол добавили окно логов - - GameWindow gameWindow = new GameWindow(); - gameWindow.setSize(400, 400); + int inset = 50; + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + int defW = screenSize.width - inset * 2; + int defH = screenSize.height - inset * 2; + + setBounds( + config.getInt("main.x", inset), + config.getInt("main.y", inset), + config.getInt("main.w", defW), + config.getInt("main.h", defH) + ); + setExtendedState(config.getInt("main.state", JFrame.NORMAL)); + + setContentPane(desktopPane); + + logWindow = createLogWindow(); + restoreInternalFrame(logWindow, "log"); + addWindow(logWindow); + + gameWindow = new GameWindow(); + restoreInternalFrame(gameWindow, "game"); addWindow(gameWindow); - setJMenuBar(generateMenuBar());//меню вверху - setDefaultCloseOperation(EXIT_ON_CLOSE);// выйти при нажатии на крестик + setJMenuBar(generateMenuBar()); + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + exitApplication(); + } + }); + } + + private void restoreInternalFrame(JInternalFrame frame, String prefix) { + int w = config.getInt(prefix + ".w", frame.getPreferredSize().width); + int h = config.getInt(prefix + ".h", frame.getPreferredSize().height); + int x = config.getInt(prefix + ".x", 10); + int y = config.getInt(prefix + ".y", 10); + + frame.setBounds(x, y, w, h); + + try { + if (config.getBool(prefix + ".max", false)) { + frame.setMaximum(true); + } else if (config.getBool(prefix + ".icon", false)) { + frame.setIcon(true); + } + } catch (PropertyVetoException e) { + } } - - protected LogWindow createLogWindow() - { - LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource());//источник сообщений передаем - logWindow.setLocation(10,10); - logWindow.setSize(300, 800); - setMinimumSize(logWindow.getSize());//главное окно не может стать меньше этого размера - logWindow.pack(); + + protected LogWindow createLogWindow() { + LogWindow lw = new LogWindow(Logger.getDefaultLogSource()); + setMinimumSize(new Dimension(300, 400)); Logger.debug("Протокол работает"); - return logWindow; + return lw; } - - protected void addWindow(JInternalFrame frame) - { + + protected void addWindow(JInternalFrame frame) { desktopPane.add(frame); frame.setVisible(true); } -// старый код меню на английском сейчас метод generatrMenuBar() -// protected JMenuBar createMenuBar() { -// JMenuBar menuBar = new JMenuBar(); -// -// //Set up the lone menu. -// JMenu menu = new JMenu("Document"); -// menu.setMnemonic(KeyEvent.VK_D); -// menuBar.add(menu); -// -// //Set up the first menu item. -// JMenuItem menuItem = new JMenuItem("New"); -// menuItem.setMnemonic(KeyEvent.VK_N); -// menuItem.setAccelerator(KeyStroke.getKeyStroke( -// KeyEvent.VK_N, ActionEvent.ALT_MASK)); -// menuItem.setActionCommand("new"); -//// menuItem.addActionListener(this); -// menu.add(menuItem); -// -// //Set up the second menu item. -// menuItem = new JMenuItem("Quit"); -// menuItem.setMnemonic(KeyEvent.VK_Q); -// menuItem.setAccelerator(KeyStroke.getKeyStroke( -// KeyEvent.VK_Q, ActionEvent.ALT_MASK)); -// menuItem.setActionCommand("quit"); -//// menuItem.addActionListener(this); -// menu.add(menuItem); -// -// return menuBar; -// } -// добавила класс для выхода - private void exitApplication(){ + + public void exitApplication() { + config.saveMain(getX(), getY(), getWidth(), getHeight(), getExtendedState()); + saveInternalFrame(logWindow, "log"); + saveInternalFrame(gameWindow, "game"); + config.save(); + UIManager.put("OptionPane.yesButtonText", "Да"); UIManager.put("OptionPane.noButtonText", "Нет"); int result = JOptionPane.showConfirmDialog( @@ -96,82 +91,24 @@ private void exitApplication(){ "Подтверждение выхода", JOptionPane.YES_NO_OPTION ); - if ( result == JOptionPane.YES_OPTION){ + if (result == JOptionPane.YES_OPTION) { System.exit(0); } - } - private JMenuBar generateMenuBar() - { - JMenuBar menuBar = new JMenuBar(); -//начала моего кода - JMenu fileMenu = new JMenu("Файл"); - fileMenu.setMnemonic(KeyEvent.VK_F); - - JMenuItem exitMenuItem = new JMenuItem("Выход"); - exitMenuItem.setMnemonic(KeyEvent.VK_X); - exitMenuItem.addActionListener((event)-> { - System.out.println("Выход из приложения"); - exitApplication(); - }); - - fileMenu.add(exitMenuItem); - - - JMenu lookAndFeelMenu = new JMenu("Режим отображения"); - lookAndFeelMenu.setMnemonic(KeyEvent.VK_V); - lookAndFeelMenu.getAccessibleContext().setAccessibleDescription( - "Управление режимом отображения приложения"); - - { - JMenuItem systemLookAndFeel = new JMenuItem("Системная схема", KeyEvent.VK_S); - systemLookAndFeel.addActionListener((event) -> { - setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - this.invalidate(); - }); - lookAndFeelMenu.add(systemLookAndFeel); // this.invalidate() - помечает контейнер как требующий перерисовки - } - { - JMenuItem crossplatformLookAndFeel = new JMenuItem("Универсальная схема", KeyEvent.VK_S); - crossplatformLookAndFeel.addActionListener((event) -> { - setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); - this.invalidate(); - }); - lookAndFeelMenu.add(crossplatformLookAndFeel); - } - - JMenu testMenu = new JMenu("Тесты"); - testMenu.setMnemonic(KeyEvent.VK_T); - testMenu.getAccessibleContext().setAccessibleDescription(//всплывающая подсказка - "Тестовые команды"); - - { - JMenuItem addLogMessageItem = new JMenuItem("Сообщение в лог", KeyEvent.VK_S); - addLogMessageItem.addActionListener((event) -> { - Logger.debug("Новая строка"); - }); - testMenu.add(addLogMessageItem); - } + private void saveInternalFrame(JInternalFrame frame, String prefix) { + config.saveInternal(prefix, frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight(), frame.isIcon(), frame.isMaximum()); + } - menuBar.add(fileMenu); - menuBar.add(lookAndFeelMenu); - menuBar.add(testMenu); - return menuBar; + private JMenuBar generateMenuBar() { + return new MenuBarBuilder(this).buildMenuBar(); } - - private void setLookAndFeel(String className)//смена оформления - { - try - { - UIManager.setLookAndFeel(className);//меняет тему - SwingUtilities.updateComponentTreeUI(this);// updateComponentTreeUI - рекурсивно обновляет все компоненты - // this - текущее окно (MainApplicationFrame) - } - catch (ClassNotFoundException | InstantiationException // Перехват возможных исключений при смене темы - | IllegalAccessException | UnsupportedLookAndFeelException e) - { - // just ignore + + public void setLookAndFeel(String className) { + try { + UIManager.setLookAndFeel(className); + SwingUtilities.updateComponentTreeUI(this); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { } } -} +} \ No newline at end of file diff --git a/robots/src/gui/RobotsProgram.java b/robots/src/gui/RobotsProgram.java index ae0930a..05896da 100644 --- a/robots/src/gui/RobotsProgram.java +++ b/robots/src/gui/RobotsProgram.java @@ -1,25 +1,19 @@ package gui; -import java.awt.Frame; - import javax.swing.SwingUtilities; import javax.swing.UIManager; -public class RobotsProgram -{ +public class RobotsProgram { public static void main(String[] args) { - try { - UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); -// UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); -// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); -// UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); - } catch (Exception e) { - e.printStackTrace(); - } - SwingUtilities.invokeLater(() -> { - MainApplicationFrame frame = new MainApplicationFrame(); - frame.pack(); - frame.setVisible(true); - frame.setExtendedState(Frame.MAXIMIZED_BOTH); - }); - }} + try { + UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + } catch (Exception e) { + e.printStackTrace(); + } + + SwingUtilities.invokeLater(() -> { + MainApplicationFrame frame = new MainApplicationFrame(); + frame.setVisible(true); + }); + } +} \ No newline at end of file diff --git a/robots/src/gui/WindowConfigManager.java b/robots/src/gui/WindowConfigManager.java new file mode 100644 index 0000000..1bd404b --- /dev/null +++ b/robots/src/gui/WindowConfigManager.java @@ -0,0 +1,64 @@ +package gui; + +import java.io.*; +import java.util.Properties; + +public class WindowConfigManager { + private static final String FILE_NAME = ".game_window_config.properties"; + private final Properties props = new Properties(); + private final File file; + + public WindowConfigManager() { + file = new File(System.getProperty("user.home"), FILE_NAME); + load(); + } + + private void load() { + if (file.exists()) { + try (FileInputStream fis = new FileInputStream(file)) { + props.load(fis); + } catch (IOException ignored) { + + } + } + } + + public void save() { + try (FileOutputStream fos = new FileOutputStream(file)) { + props.store(fos, "Application Window Configuration"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public int getInt(String key, int def) { + String val = props.getProperty(key); + try { + return val != null ? Integer.parseInt(val) : def; + } catch (NumberFormatException e) { + return def; + } + } + + public boolean getBool(String key, boolean def) { + String val = props.getProperty(key); + return val != null ? Boolean.parseBoolean(val) : def; + } + + public void saveMain(int x, int y, int w, int h, int state) { + props.setProperty("main.x", String.valueOf(x)); + props.setProperty("main.y", String.valueOf(y)); + props.setProperty("main.w", String.valueOf(w)); + props.setProperty("main.h", String.valueOf(h)); + props.setProperty("main.state", String.valueOf(state)); + } + + public void saveInternal(String prefix, int x, int y, int w, int h, boolean iconified, boolean maximized) { + props.setProperty(prefix + ".x", String.valueOf(x)); + props.setProperty(prefix + ".y", String.valueOf(y)); + props.setProperty(prefix + ".w", String.valueOf(w)); + props.setProperty(prefix + ".h", String.valueOf(h)); + props.setProperty(prefix + ".icon", String.valueOf(iconified)); + props.setProperty(prefix + ".max", String.valueOf(maximized)); + } +} \ No newline at end of file From 35935d55f452e03557fea24aced41098bd29952d Mon Sep 17 00:00:00 2001 From: zhukovskaia Date: Fri, 17 Apr 2026 18:01:09 +0500 Subject: [PATCH 3/6] =?UTF-8?q?task-02=20=D1=83=D0=B1=D1=80=D0=B0=D0=BB?= =?UTF-8?q?=D0=B0=20idea?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 3 --- .idea/Robots.iml | 12 ------------ .idea/misc.xml | 6 ------ .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ out/production/Robots/.classpath | 6 ------ out/production/Robots/.gitignore | 2 -- out/production/Robots/.project | 17 ----------------- .../Robots/gui/GameVisualizer$1.class | Bin 575 -> 0 bytes .../Robots/gui/GameVisualizer$2.class | Bin 580 -> 0 bytes .../Robots/gui/GameVisualizer$3.class | Bin 803 -> 0 bytes out/production/Robots/gui/GameVisualizer.class | Bin 5627 -> 0 bytes out/production/Robots/gui/GameWindow.class | Bin 856 -> 0 bytes out/production/Robots/gui/LogWindow.class | Bin 2580 -> 0 bytes .../Robots/gui/MainApplicationFrame.class | Bin 6128 -> 0 bytes out/production/Robots/gui/RobotsProgram.class | Bin 1542 -> 0 bytes .../Robots/log/LogChangeListener.class | Bin 148 -> 0 bytes out/production/Robots/log/LogEntry.class | Bin 651 -> 0 bytes out/production/Robots/log/LogLevel.class | Bin 1341 -> 0 bytes .../Robots/log/LogWindowSource.class | Bin 2507 -> 0 bytes out/production/Robots/log/Logger.class | Bin 858 -> 0 bytes 21 files changed, 60 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/Robots.iml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 out/production/Robots/.classpath delete mode 100644 out/production/Robots/.gitignore delete mode 100644 out/production/Robots/.project delete mode 100644 out/production/Robots/gui/GameVisualizer$1.class delete mode 100644 out/production/Robots/gui/GameVisualizer$2.class delete mode 100644 out/production/Robots/gui/GameVisualizer$3.class delete mode 100644 out/production/Robots/gui/GameVisualizer.class delete mode 100644 out/production/Robots/gui/GameWindow.class delete mode 100644 out/production/Robots/gui/LogWindow.class delete mode 100644 out/production/Robots/gui/MainApplicationFrame.class delete mode 100644 out/production/Robots/gui/RobotsProgram.class delete mode 100644 out/production/Robots/log/LogChangeListener.class delete mode 100644 out/production/Robots/log/LogEntry.class delete mode 100644 out/production/Robots/log/LogLevel.class delete mode 100644 out/production/Robots/log/LogWindowSource.class delete mode 100644 out/production/Robots/log/Logger.class diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/Robots.iml b/.idea/Robots.iml deleted file mode 100644 index d58e90e..0000000 --- a/.idea/Robots.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index fbd542f..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 650a132..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/out/production/Robots/.classpath b/out/production/Robots/.classpath deleted file mode 100644 index fceb480..0000000 --- a/out/production/Robots/.classpath +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/out/production/Robots/.gitignore b/out/production/Robots/.gitignore deleted file mode 100644 index 2757ffa..0000000 --- a/out/production/Robots/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/bin/ -/.settings/ diff --git a/out/production/Robots/.project b/out/production/Robots/.project deleted file mode 100644 index 78e1656..0000000 --- a/out/production/Robots/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - Robots - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/out/production/Robots/gui/GameVisualizer$1.class b/out/production/Robots/gui/GameVisualizer$1.class deleted file mode 100644 index f1c0ca4485b43db7ec3ff2526522fded4fa46813..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 575 zcmZvZOHaZ;5Xb+Em6lQ-g5ukFAQ8}rUc8`Q2tE?@poaSj8(l5iq}yWRw=(gOc<=-G zp^USY#2DFRcXp=#`OWO~^XvTszya1WNMXu`4@l`rPmFP#S+6 zw9H!=Didhc-4^v1#)`qc4C1gaj-=s~|4wAvJdo;jRNoJ@R5xcLx(x;l&biRhNua4) z?^G!fwtcR(&{(G_J2Y@sESfpfEk!$v5(rMWL-I|;ZEU`PHQr!9C7M|})1(15Fh^(Q zM@4p?JklpLMv4V^W7Zy7li@U;!CsO3CAmrVCTwgaG?PKPG0nmvc_}PmnXE;BD1((G NlE*4pm(-?5THil}aOeO4 diff --git a/out/production/Robots/gui/GameVisualizer$2.class b/out/production/Robots/gui/GameVisualizer$2.class deleted file mode 100644 index 342880fb9930a99e0a5e8fc390d5bc4756ea5249..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 580 zcmZvZ%TB^T6o&u7N}*IiK=2+HEC3TRXxyM|3|izurFp9AYDl1ZHelE@qKrC|*ahal*%9Aa%q&`6z-)lOY-2 zNL|^X@7-xb%Rvfh8;*+%T!z9ef8dQMlwRXPjzw_6^&KG&q>^EqVWwIeIG9J)M$W~8 zsmM=5N%U3E9|`aBe#Ar3c@QdOC|Cb$pf+Hzj>ycA?Mfy3(fG=od*zXm@A^aT4R|0; zJ`pW*A%@aFv`Vu@O$L!-aL)ZG7>Z+QIEBAs**3SN^Ezti`C6*$o(OOJ5ksmkba?7( z>ef9|N(4t9*IH<7(x_83b(YJSVbd-_Zw7e~oOW%>jpEd|Ucl;au%BX2k=7)6fCd(6 zE&aGCmMJ5DOk?C&f;(aDQ#2K+`ZL%o=6*>|T)hh$doj&akZ(e>uuNG3D_Esy(Qis) PEmr2SPSGK^>5-mqH&Sx; diff --git a/out/production/Robots/gui/GameVisualizer$3.class b/out/production/Robots/gui/GameVisualizer$3.class deleted file mode 100644 index 0892b40354895aaa6866a51ed921f43e7702fd18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 803 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 diff --git a/out/production/Robots/gui/GameWindow.class b/out/production/Robots/gui/GameWindow.class deleted file mode 100644 index ecd8e5c3f3e21fb9bb91d59ba1cb775cd79e4927..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856 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 diff --git a/out/production/Robots/gui/RobotsProgram.class b/out/production/Robots/gui/RobotsProgram.class deleted file mode 100644 index 04382b3dec85dbbb562b64b12be38eb162bd79cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1542 zcma)6U31e$6g_J@mLnAGIE@q1HjofXY+4KGcgFJaNG0_xhU{u}zkmWm)g&F&Y>jM>Pq(8gSftvOkNNiuBq;( z5WWo?XDm1lrf`;FHUYW`(0#n!aH+nZC z-WN6&ku}4zgNsIaE+ow+aLK_pxXfUaE&DQ-q>ffspBTm}xs^D;Uut*EbH%~8_>Q)Z z5F1BYsIKUe1vaQc}^AO6&~!Z4vDmGZ@NV(Bb|* zkED4Y1#|kDr0!?DPna4+)u$$nyH8W@j`xm%5$kMfX}o&|%cGtlJ_X7!m275{ha(kJ zKJT}?e8tpTxymqcVCCwX@_AZK*M!=}*Bf^J;Q zW8KE@*s!qa;2yRZmQN1f@C3MCqJPrv<_J{%*^u)r2qU0=j2=Hw5; zM#`FzYpKXbz`a+YNT>h*#bL?MW78kUhjd79KGyem<2hpP@NeqKX;%l7TE}$C0P;D!sWhGnyxAZ@^yDpA4?i zXqJHjuG8oY6YxELptni9PuM)3wc7BX8Fin)?)Y#RyKC4dn+ z|2G!@e1i-3YsXls<&LpZE9H+-J87swMM1&}RLopv)0m^*{J23Q=O%7ZP8PRm%-{~z YXg1B?rPwz9pr=U@n<6`Sh+Ulf04ywh%>V!Z diff --git a/out/production/Robots/log/LogChangeListener.class b/out/production/Robots/log/LogChangeListener.class deleted file mode 100644 index 7788a76dcc82402829e0144685c8bb3ed8c7996d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmX^0Z`VEs1_oOOPId++Mh4NG{B(Vv{B-Ax#Ju!WpUmQt)V$Opb_Nzk27#=^vPAtH zpt!z&QdVkm2_pkfejZ$H3L^uvhGrNe16Ocb|A^bzySb6Z6o>s diff --git a/out/production/Robots/log/LogEntry.class b/out/production/Robots/log/LogEntry.class deleted file mode 100644 index 6dbb11497b76d2a822f5e5064660ad55c259a303..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 651 zcmZuu%TB^j5IwgP3Z+0r@coP%sK$N(>c;4*>H7@|_(_~(qbI#1%ukVjf0O#0OAt9qc){sSxK_A#-+w^STG4FZ<-j5k_XRhzY7Yvz3 zvr|AG1qG^xA~Xig3mnr5oGU*LpD7)7qd2_bQDi%up=!<8+HvUmPAkEeHB_K8sKYM7 zEk5QRL)l8HMBZXJYW%G%b2U2*@@4QyN)^lX`R!=f+NQ)8sBVq+3Yz z3KD&E5E0Q;$!EamIabJ4DSJqshkaVO0NR2O127_Y=Nvwwumy3)TnYW zg`ti$%7_5#B*R3sK|K=1o7hTaO!CRUtnmirg#rl)c}^5{L8wg|QbLAp>`*0{aUNV+ M1lRus?+S^%A7Mmzf&c&j diff --git a/out/production/Robots/log/LogLevel.class b/out/production/Robots/log/LogLevel.class deleted file mode 100644 index cea0168ac7bcbc95579ec49bb65da83bb93ea19c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1341 zcmZuw+fvg|6kVseHUuc;CKnL_wJl0T!CMhgE?Vu#LlCFKgA;0~VbXLawETp>;)50y zMn}hIKgx0M(=xU~9uqUOWBDhGOO^m4#>?M9&=N>HDTq@=A!Q8i-J zfQ>;J*>G#FtUhex0!D~8v;Da6YTXg&-RW$=!WhO4jM%t{32L(xR6}ZWAeAocyN7Nz zaKmzTb9dh>)p8alaoNC>jcLqKQ~v<#VZB0C4&9*cZSDyyrrOx6fqQU}YYRBFh-S#O zSKtIP|5Y2;kP^_B{Lrs03kCNzuAvYh9p!0>r= z;+u$@uub%uNSYXA%3T}xaG%AJa~uftrPBY&MU9;vs;kwvq*QOg551T5%B~k}xw`>H zrp_su?o?eMS*VuWVB3v+CbgJq=vF8}@~l?03$=GXwWOa;8h8A1=+^2H5!4h-M3)!v z)(I%7be>dMDg`YKDL}`QZE0EWrOuv~a{`uAtw$wq!{<4=Pxp9^FM4I3B$}jEH&;e@ zr2(?Ex6;zKN=r*BEiI#!b>cn1eae?3Z;C8GRs%y{G5QN*AITF~ zqPH&36v9u_FV@5_P(Ef@Ns&3hrC$(?k9FXeDPlKKc!U*sPU}D@uJ{ZJR7PZG$B%I( zbMXt(pCpEB_RuN#cS8bQ=mX~(A|_{iEa%~`Cp3|QRf@*2MwQmF(dsWtmiyB(pOO9` z0slrBl~wLW&{1s zS+Pt!r4gHAy{D_0$jO3#qqElrc2CB56aF1>E)Ef|LM64F~V uP3iTY;LZ_-Sh?nHO~9aUjTF=|PTv`rG+LaLv9LvI#aeph@tklmy!Z>;fvxcaS7U%+SuPs|vn@7yGI^uHPL;PzYL_()i58@BQpY=zY~8WRT{Wa-Y5KH|QJf(WW$SD5NW!yG zoW+=ijE-@fBdl!>CY@rD0Y^<)DHj5>~2$W38Sj|^ewk*xE=T22?Q|4itP+!Jm)0EY3 zLawYT*4Z}63Tc*kkwBTY=CWtF-euP*(Q@9Y*wlo^u4CSvbz}w9)$!WJUDyv8#iGFe znnqtcPCv(Y-PpxWwA$@1TT%%7SVxUK56gTY!M4)GHXG!V?UJ)5+1DU&Ma{G5kUgvZ z{voS_J&1c6*Vq#I{D^O+vH&E~TM+5^2DJ1Ov@XQA(6)gNHQ&Pi4Rk+LW^;V*=XIcm z7h`C~0Xm7(^g&FiJqap-XD)YY7Af-K_7RIpdCkv;1~|G6K*5ut0U;c3})&1Q(Eak z(<_?cHz}eatFF!vYH2z>T$_>TNnd@14^AihE38zR2p|AlV>scQa2hIpG9&H5Ac zFANNB;jL+=uwzK2@DX~)g0bKWjH>L8g=BhrUmzx51HT}>iNRlSVl0@B1)1$wi0N(_ z3v-NxpT&Y>p;+kYXgDycb!lDUd+3gZy0nvHkyzv>ye;sJChoubLlSeGO*BgoSteSJ zRbocjUxAZ|@*~iRQxwQ)^x_OppJfU%{82EDNlZ`-=W&~gbUEI|MU|Kdgt?|Ex*{^X zI)&@FjvEYKu6>R#=sgMtUt*D7W4Ot`1XCgj?nCG$CN=bHI6-tAsKim3gXd;x5kxgR~x7N78Hp} zAn^fw6k^tPfYRUxd(U{!oSE7E@$>6<0FSX_p@OOj!$u8r0_{Wp#P7v^682sX59KHm znA?q#D0?DMb=*M%bu>&^Hkz;ntT+vOUK)l{u{V$h{v^&=@23+rk^&vC-0(I^g7iZH z_Zw(o!9?4}B9;W~a*roZWGqnIlfy|U(3zV)f;~p z6It@oksl9y73sPJjqH6irlaX_=F%s5P&n#1vt%&Eai(6%@z@V@-V0L6AhkTY4rR7? zA>}p4oen&gvp{`!6ql!G72!XRwD=~^h}w4aC_LbqR(Kl(*7d1!Rb$QTK;$~Bhx`hS zcF!O_aZ$kyzV*!k8w|GG Date: Fri, 17 Apr 2026 18:06:06 +0500 Subject: [PATCH 4/6] task-02 --- robots/src/gui/GameVisualizer.java | 13 ++++---- robots/src/gui/GameWindow.java | 2 +- robots/src/gui/LogWindow.java | 51 +++++++++++++----------------- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/robots/src/gui/GameVisualizer.java b/robots/src/gui/GameVisualizer.java index 9a533bf..6f9d9a4 100644 --- a/robots/src/gui/GameVisualizer.java +++ b/robots/src/gui/GameVisualizer.java @@ -4,10 +4,10 @@ import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Point;// хранения координат точки (x, y) +import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; //для трансформации графики (поворот, масштабирование) +import java.awt.geom.AffineTransform; import java.util.Timer; import java.util.TimerTask; @@ -15,18 +15,18 @@ public class GameVisualizer extends JPanel { - private final Timer m_timer = initTimer(); // Timer - класс для выполнения задач по расписанию + private final Timer m_timer = initTimer(); private static Timer initTimer() { Timer timer = new Timer("events generator", true); - return timer; // true - таймер работает как демон-поток (завершится при завершении программы) + return timer; } private volatile double m_robotPositionX = 100; private volatile double m_robotPositionY = 100; private volatile double m_robotDirection = 0; - // Направление робота в радианах (0 - смотрит направо) + private volatile int m_targetPositionX = 150; private volatile int m_targetPositionY = 100; @@ -35,6 +35,7 @@ private static Timer initTimer() public GameVisualizer() { + m_timer.schedule(new TimerTask() { @Override @@ -98,7 +99,7 @@ protected void onModelUpdateEvent() return; } double velocity = maxVelocity; - double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, m_targetPositionX, m_targetPositionY); + double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, m_targetPositionX, m_targetPositionY);// поворачиваем если надо налево направо double angularVelocity = 0; if (angleToTarget > m_robotDirection) { diff --git a/robots/src/gui/GameWindow.java b/robots/src/gui/GameWindow.java index 8919767..ecb63c0 100644 --- a/robots/src/gui/GameWindow.java +++ b/robots/src/gui/GameWindow.java @@ -7,7 +7,7 @@ public class GameWindow extends JInternalFrame { - private final GameVisualizer m_visualizer; // Приватное поле для хранения ссылки на визуализатор игры + private final GameVisualizer m_visualizer; public GameWindow() { super("Игровое поле", true, true, true, true); diff --git a/robots/src/gui/LogWindow.java b/robots/src/gui/LogWindow.java index 5c01d5d..901d8df 100644 --- a/robots/src/gui/LogWindow.java +++ b/robots/src/gui/LogWindow.java @@ -1,55 +1,48 @@ package gui; -import java.awt.BorderLayout; // BorderLayout делит область на 5 частей: NORTH, SOUTH, EAST, WEST, CENTER -import java.awt.EventQueue;// Позволяет выполнять код в потоке обработки событий -import java.awt.TextArea;// Импорт класса TextArea - многострочное текстовое поле (устаревшее, но простое) - +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.TextArea; import javax.swing.JInternalFrame; import javax.swing.JPanel; - -import log.LogChangeListener; // Импорт интерфейса LogChangeListener - для получения уведомлений об изменениях в логе -import log.LogEntry;// Импорт класса LogEntry - представляет одну запись в логе (одно сообщение) +import log.LogChangeListener; import log.LogEntry; -import log.LogWindowSource;// Импорт класса LogWindowSource - источник логов (где хранятся сообщения) +import log.LogWindowSource; public class LogWindow extends JInternalFrame implements LogChangeListener { - private LogWindowSource m_logSource;// ссылка на источник логов - private TextArea m_logContent; // текст с сообщением + private LogWindowSource m_logSource; + private TextArea m_logContent; - public LogWindow(LogWindowSource logSource) + public LogWindow(LogWindowSource logSource) { super("Протокол работы", true, true, true, true); m_logSource = logSource; - m_logSource.registerListener(this);// Регистрируем это окно как слушателя изменений в источнике логов - // registerListener - добавляет подписчика, который будет уведомляться об изменениях - m_logContent = new TextArea("");// новое текстовое поле + m_logSource.registerListener(this); + m_logContent = new TextArea(""); m_logContent.setSize(200, 500); - - JPanel panel = new JPanel(new BorderLayout()); // Создаем панель с менеджером компоновки BorderLayout - panel.add(m_logContent, BorderLayout.CENTER);// Добавляем текстовое поле в центр панели - getContentPane().add(panel); // Получаем панель содержимого внутреннего окна и добавляем нашу панель - // getContentPane() - возвращает контейнер для содержимого окна + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(m_logContent, BorderLayout.CENTER); + getContentPane().add(panel); pack(); - updateLogContent(); // Загружаем существующее содержимое лога в текстовое поле + updateLogContent(); } private void updateLogContent() { - StringBuilder content = new StringBuilder();// Создаем StringBuilder для эффективного построения строки - // StringBuilder лучше, чем простая конкатенация строк через + - for (LogEntry entry : m_logSource.all()) // Проходим по всем записям в источнике лога - + StringBuilder content = new StringBuilder(); + for (LogEntry entry : m_logSource.all()) { - content.append(entry.getMessage()).append("\n"); // Добавляем сообщение из записи и перевод строки + content.append(entry.getMessage()).append("\n"); } - m_logContent.setText(content.toString()); // Устанавливаем полученный текст в текстовое поле + m_logContent.setText(content.toString()); m_logContent.invalidate(); } - - @Override // Выполняем обновление содержимого в потоке обработки событий + + @Override public void onLogChanged() { EventQueue.invokeLater(this::updateLogContent); } -} +} \ No newline at end of file From 94891f36aba20b12de1b50f745d29da547f6e2f3 Mon Sep 17 00:00:00 2001 From: zhukovskaia Date: Mon, 27 Apr 2026 18:18:00 +0500 Subject: [PATCH 5/6] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=20task2,=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B0=20=D0=B2=D1=81=D0=B5=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B6=D0=B5=D0=BB=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robots/src/gui/AppStateManager.java | 76 ++++++++++++++++++++++++ robots/src/gui/MainApplicationFrame.java | 70 +++++++++------------- robots/src/gui/WindowConfigManager.java | 17 ++++-- 3 files changed, 114 insertions(+), 49 deletions(-) create mode 100644 robots/src/gui/AppStateManager.java diff --git a/robots/src/gui/AppStateManager.java b/robots/src/gui/AppStateManager.java new file mode 100644 index 0000000..1404641 --- /dev/null +++ b/robots/src/gui/AppStateManager.java @@ -0,0 +1,76 @@ +package gui; + +import java.beans.PropertyVetoException; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import log.Logger; + +public class AppStateManager { + private final WindowConfigManager configManager; + + public AppStateManager() { + this.configManager = new WindowConfigManager(); + } + + public void load() { + configManager.load(); + Logger.debug("Менеджер состояний: загрузка конфигурации запущена"); + } + + public void save() { + configManager.save(); + } + + public void restoreMain(JFrame mainFrame, int defaultX, int defaultY, int defaultW, int defaultH) { + mainFrame.setBounds( + configManager.getInt("main.x", defaultX), + configManager.getInt("main.y", defaultY), + configManager.getInt("main.w", defaultW), + configManager.getInt("main.h", defaultH) + ); + mainFrame.setExtendedState(configManager.getInt("main.state", JFrame.NORMAL)); + } + + public void restoreInternalFrame(JInternalFrame frame, String prefix, int defaultX, int defaultY, int defaultW, int defaultH) { + int w = configManager.getInt(prefix + ".w", defaultW); + int h = configManager.getInt(prefix + ".h", defaultH); + int x = configManager.getInt(prefix + ".x", defaultX); + int y = configManager.getInt(prefix + ".y", defaultY); + + frame.setBounds(x, y, w, h); + + try { + if (configManager.getBool(prefix + ".max", false)) { + frame.setMaximum(true); + } else if (configManager.getBool(prefix + ".icon", false)) { + frame.setIcon(true); + } + } catch (PropertyVetoException e) { + Logger.error("Не удалось восстановить состояние окна '" + prefix + "': " + e.getMessage()); + } + } + + public void saveMain(JFrame mainFrame) { + configManager.saveMain( + mainFrame.getX(), mainFrame.getY(), + mainFrame.getWidth(), mainFrame.getHeight(), + mainFrame.getExtendedState() + ); + } + + public void saveInternalFrame(JInternalFrame frame, String prefix) { + configManager.saveInternal(prefix, + frame.getX(), frame.getY(), + frame.getWidth(), frame.getHeight(), + frame.isIcon(), frame.isMaximum() + ); + } + + public void saveAllFrames(JDesktopPane desktopPane) { + for (JInternalFrame frame : desktopPane.getAllFrames()) { + String prefix = frame.getTitle().replaceAll("\\s+", "_").toLowerCase(); + saveInternalFrame(frame, prefix); + } + } +} \ No newline at end of file diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index 6e8fd6f..d2aa0fc 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -1,8 +1,6 @@ package gui; - import java.awt.Dimension; import java.awt.Toolkit; -import java.beans.PropertyVetoException; import javax.swing.*; import log.Logger; @@ -10,30 +8,33 @@ public class MainApplicationFrame extends JFrame { private final JDesktopPane desktopPane = new JDesktopPane(); private LogWindow logWindow; private GameWindow gameWindow; - private final WindowConfigManager config = new WindowConfigManager(); + private final AppStateManager stateManager = new AppStateManager(); + + private static final int DEFAULT_INSET = 50; + private static final int DEFAULT_INTERNAL_WIDTH = 600; + private static final int DEFAULT_INTERNAL_HEIGHT = 400; + private static final int DEFAULT_GAME_X = 10; + private static final int DEFAULT_GAME_Y = 10; + private static final int DEFAULT_LOG_X = 220; + private static final int DEFAULT_LOG_Y = 10; public MainApplicationFrame() { - int inset = 50; + stateManager.load(); + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - int defW = screenSize.width - inset * 2; - int defH = screenSize.height - inset * 2; - - setBounds( - config.getInt("main.x", inset), - config.getInt("main.y", inset), - config.getInt("main.w", defW), - config.getInt("main.h", defH) - ); - setExtendedState(config.getInt("main.state", JFrame.NORMAL)); + int defW = screenSize.width - DEFAULT_INSET * 2; + int defH = screenSize.height - DEFAULT_INSET * 2; + + stateManager.restoreMain(this, DEFAULT_INSET, DEFAULT_INSET, defW, defH); setContentPane(desktopPane); logWindow = createLogWindow(); - restoreInternalFrame(logWindow, "log"); + stateManager.restoreInternalFrame(logWindow, "log", DEFAULT_LOG_X, DEFAULT_LOG_Y, DEFAULT_INTERNAL_WIDTH, DEFAULT_INTERNAL_HEIGHT); addWindow(logWindow); gameWindow = new GameWindow(); - restoreInternalFrame(gameWindow, "game"); + stateManager.restoreInternalFrame(gameWindow, "game", DEFAULT_GAME_X, DEFAULT_GAME_Y, DEFAULT_INTERNAL_WIDTH, DEFAULT_INTERNAL_HEIGHT); addWindow(gameWindow); setJMenuBar(generateMenuBar()); @@ -45,29 +46,12 @@ public void windowClosing(java.awt.event.WindowEvent e) { exitApplication(); } }); - } - - private void restoreInternalFrame(JInternalFrame frame, String prefix) { - int w = config.getInt(prefix + ".w", frame.getPreferredSize().width); - int h = config.getInt(prefix + ".h", frame.getPreferredSize().height); - int x = config.getInt(prefix + ".x", 10); - int y = config.getInt(prefix + ".y", 10); - frame.setBounds(x, y, w, h); - - try { - if (config.getBool(prefix + ".max", false)) { - frame.setMaximum(true); - } else if (config.getBool(prefix + ".icon", false)) { - frame.setIcon(true); - } - } catch (PropertyVetoException e) { - } + Logger.debug("Главное окно инициализировано"); } protected LogWindow createLogWindow() { LogWindow lw = new LogWindow(Logger.getDefaultLogSource()); - setMinimumSize(new Dimension(300, 400)); Logger.debug("Протокол работает"); return lw; } @@ -78,10 +62,11 @@ protected void addWindow(JInternalFrame frame) { } public void exitApplication() { - config.saveMain(getX(), getY(), getWidth(), getHeight(), getExtendedState()); - saveInternalFrame(logWindow, "log"); - saveInternalFrame(gameWindow, "game"); - config.save(); + stateManager.saveMain(this); + stateManager.saveAllFrames(desktopPane); + stateManager.save(); + + Logger.debug("Конфигурация сохранена перед выходом"); UIManager.put("OptionPane.yesButtonText", "Да"); UIManager.put("OptionPane.noButtonText", "Нет"); @@ -92,14 +77,11 @@ public void exitApplication() { JOptionPane.YES_NO_OPTION ); if (result == JOptionPane.YES_OPTION) { + Logger.debug("Приложение закрыто пользователем"); System.exit(0); } } - private void saveInternalFrame(JInternalFrame frame, String prefix) { - config.saveInternal(prefix, frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight(), frame.isIcon(), frame.isMaximum()); - } - private JMenuBar generateMenuBar() { return new MenuBarBuilder(this).buildMenuBar(); } @@ -108,7 +90,9 @@ public void setLookAndFeel(String className) { try { UIManager.setLookAndFeel(className); SwingUtilities.updateComponentTreeUI(this); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { + Logger.debug("Тема оформления изменена: " + className); + } catch (Exception e) { + Logger.error("Не удалось установить тему оформления: " + e.getMessage()); } } } \ No newline at end of file diff --git a/robots/src/gui/WindowConfigManager.java b/robots/src/gui/WindowConfigManager.java index 1bd404b..3cb7a07 100644 --- a/robots/src/gui/WindowConfigManager.java +++ b/robots/src/gui/WindowConfigManager.java @@ -1,7 +1,7 @@ package gui; - import java.io.*; import java.util.Properties; +import log.Logger; public class WindowConfigManager { private static final String FILE_NAME = ".game_window_config.properties"; @@ -10,24 +10,28 @@ public class WindowConfigManager { public WindowConfigManager() { file = new File(System.getProperty("user.home"), FILE_NAME); - load(); + } - private void load() { + public void load() { if (file.exists()) { try (FileInputStream fis = new FileInputStream(file)) { props.load(fis); - } catch (IOException ignored) { - + Logger.debug("Конфигурация загружена успешно"); + } catch (IOException e) { + Logger.error("Не удалось загрузить конфигурацию: " + e.getMessage()); } + } else { + Logger.debug("Файл конфигурации не найден, используются значения по умолчанию"); } } public void save() { try (FileOutputStream fos = new FileOutputStream(file)) { props.store(fos, "Application Window Configuration"); + } catch (IOException e) { - e.printStackTrace(); + Logger.error("Не удалось сохранить конфигурацию: " + e.getMessage()); } } @@ -36,6 +40,7 @@ public int getInt(String key, int def) { try { return val != null ? Integer.parseInt(val) : def; } catch (NumberFormatException e) { + Logger.error("Неверный формат числа для ключа '" + key + "': " + val); return def; } } From 5d0f835f99d4eec4eaf7756e69810f4ee8c0c3a5 Mon Sep 17 00:00:00 2001 From: zhukovskaia Date: Tue, 5 May 2026 17:43:24 +0500 Subject: [PATCH 6/6] =?UTF-8?q?=D0=B2=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=D0=B0=203=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robots/src/gui/GameVisualizer.java | 220 ++++------------------- robots/src/gui/GameWindow.java | 23 ++- robots/src/gui/LogWindow.java | 45 ++--- robots/src/gui/MainApplicationFrame.java | 59 +++--- robots/src/gui/MenuBarBuilder.java | 48 +++++ robots/src/gui/RobotInfoWindow.java | 53 ++++++ robots/src/gui/RobotModel.java | 81 +++++++++ robots/src/gui/WindowConfigManager.java | 28 ++- robots/src/log/LogWindowSource.java | 116 +++++------- 9 files changed, 335 insertions(+), 338 deletions(-) create mode 100644 robots/src/gui/MenuBarBuilder.java create mode 100644 robots/src/gui/RobotInfoWindow.java create mode 100644 robots/src/gui/RobotModel.java diff --git a/robots/src/gui/GameVisualizer.java b/robots/src/gui/GameVisualizer.java index 6f9d9a4..785cd4c 100644 --- a/robots/src/gui/GameVisualizer.java +++ b/robots/src/gui/GameVisualizer.java @@ -4,208 +4,64 @@ import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.util.Timer; import java.util.TimerTask; - import javax.swing.JPanel; -public class GameVisualizer extends JPanel -{ - private final Timer m_timer = initTimer(); - - private static Timer initTimer() - { - Timer timer = new Timer("events generator", true); - return timer; - } - - private volatile double m_robotPositionX = 100; - private volatile double m_robotPositionY = 100; - private volatile double m_robotDirection = 0; +public class GameVisualizer extends JPanel implements RobotModel.Observer { + private final RobotModel model; + private final Timer timer = new Timer("events generator", true); - private volatile int m_targetPositionX = 150; - private volatile int m_targetPositionY = 100; - - private static final double maxVelocity = 0.1; //ЛИНЕЙНАЯ - private static final double maxAngularVelocity = 0.001;// УГЛОВАЯ - - public GameVisualizer() - { + public GameVisualizer(RobotModel model) { + this.model = model; + model.addObserver(this); // Подписываемся на обновления - m_timer.schedule(new TimerTask() - { - @Override - public void run() - { - onRedrawEvent(); - } + timer.schedule(new TimerTask() { + @Override public void run() { EventQueue.invokeLater(GameVisualizer.this::repaint); } }, 0, 50); - m_timer.schedule(new TimerTask() - { - @Override - public void run() - { - onModelUpdateEvent(); - } + + timer.schedule(new TimerTask() { + @Override public void run() { model.update(); } }, 0, 10); - addMouseListener(new MouseAdapter() - { - @Override - public void mouseClicked(MouseEvent e) - { - setTargetPosition(e.getPoint()); - repaint(); + + addMouseListener(new MouseAdapter() { + @Override public void mouseClicked(MouseEvent e) { + model.setTarget(e.getX(), e.getY()); } }); setDoubleBuffered(true); } - protected void setTargetPosition(Point p) - { - m_targetPositionX = p.x; - m_targetPositionY = p.y; - } - - protected void onRedrawEvent() - { - EventQueue.invokeLater(this::repaint); - } + private static int round(double v) { return (int)(v + 0.5); } - private static double distance(double x1, double y1, double x2, double y2) - { - double diffX = x1 - x2; - double diffY = y1 - y2; - return Math.sqrt(diffX * diffX + diffY * diffY); - } - - private static double angleTo(double fromX, double fromY, double toX, double toY) - { - double diffX = toX - fromX; - double diffY = toY - fromY; - - return asNormalizedRadians(Math.atan2(diffY, diffX)); - } - - protected void onModelUpdateEvent() - { - double distance = distance(m_targetPositionX, m_targetPositionY, - m_robotPositionX, m_robotPositionY); - if (distance < 0.5) - { - return; - } - double velocity = maxVelocity; - double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, m_targetPositionX, m_targetPositionY);// поворачиваем если надо налево направо - double angularVelocity = 0; - if (angleToTarget > m_robotDirection) - { - angularVelocity = maxAngularVelocity; - } - if (angleToTarget < m_robotDirection) - { - angularVelocity = -maxAngularVelocity; - } - - moveRobot(velocity, angularVelocity, 10); - } - - private static double applyLimits(double value, double min, double max) - { - if (value < min) - return min; - if (value > max) - return max; - return value; - } - - private void moveRobot(double velocity, double angularVelocity, double duration) - { - velocity = applyLimits(velocity, 0, maxVelocity); - angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity); - double newX = m_robotPositionX + velocity / angularVelocity * - (Math.sin(m_robotDirection + angularVelocity * duration) - - Math.sin(m_robotDirection)); - if (!Double.isFinite(newX)) - { - newX = m_robotPositionX + velocity * duration * Math.cos(m_robotDirection); - } - double newY = m_robotPositionY - velocity / angularVelocity * - (Math.cos(m_robotDirection + angularVelocity * duration) - - Math.cos(m_robotDirection)); - if (!Double.isFinite(newY)) - { - newY = m_robotPositionY + velocity * duration * Math.sin(m_robotDirection); - } - m_robotPositionX = newX; - m_robotPositionY = newY; - double newDirection = asNormalizedRadians(m_robotDirection + angularVelocity * duration); - m_robotDirection = newDirection; - } - - private static double asNormalizedRadians(double angle) - { - while (angle < 0) - { - angle += 2*Math.PI; - } - while (angle >= 2*Math.PI) - { - angle -= 2*Math.PI; - } - return angle; - } - - private static int round(double value) - { - return (int)(value + 0.5); - } - @Override - public void paint(Graphics g) - { + public void paint(Graphics g) { super.paint(g); - Graphics2D g2d = (Graphics2D)g; - drawRobot(g2d, round(m_robotPositionX), round(m_robotPositionY), m_robotDirection); - drawTarget(g2d, m_targetPositionX, m_targetPositionY); + Graphics2D g2d = (Graphics2D) g; + drawRobot(g2d, round(model.getX()), round(model.getY()), model.getDir()); + drawTarget(g2d, model.getTargetX(), model.getTargetY()); } - - private static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2) - { - g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); - } - - private static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2) - { - g.drawOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); + + private void drawRobot(Graphics2D g, int x, int y, double dir) { + g.setTransform(AffineTransform.getRotateInstance(dir, x, y)); + g.setColor(Color.MAGENTA); g.fillOval(x-15, y-5, 30, 10); + g.setColor(Color.BLACK); g.drawOval(x-15, y-5, 30, 10); + g.setColor(Color.WHITE); g.fillOval(x+5, y-2, 5, 5); + g.setColor(Color.BLACK); g.drawOval(x+5, y-2, 5, 5); } - - private void drawRobot(Graphics2D g, int x, int y, double direction) - { - int robotCenterX = round(m_robotPositionX); - int robotCenterY = round(m_robotPositionY); - AffineTransform t = AffineTransform.getRotateInstance(direction, robotCenterX, robotCenterY); - g.setTransform(t); - g.setColor(Color.MAGENTA); - fillOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.BLACK); - drawOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.WHITE); - fillOval(g, robotCenterX + 10, robotCenterY, 5, 5); - g.setColor(Color.BLACK); - drawOval(g, robotCenterX + 10, robotCenterY, 5, 5); + + private void drawTarget(Graphics2D g, int x, int y) { + g.setTransform(new AffineTransform()); + g.setColor(Color.GREEN); g.fillOval(x-2, y-2, 5, 5); + g.setColor(Color.BLACK); g.drawOval(x-2, y-2, 5, 5); } - - private void drawTarget(Graphics2D g, int x, int y) - { - AffineTransform t = AffineTransform.getRotateInstance(0, 0, 0); - g.setTransform(t); - g.setColor(Color.GREEN); - fillOval(g, x, y, 5, 5); - g.setColor(Color.BLACK); - drawOval(g, x, y, 5, 5); + + @Override + public void onStateChanged(double x, double y, double dir, int tx, int ty) { + // Перерисовка при изменении модели + repaint(); } -} +} \ No newline at end of file diff --git a/robots/src/gui/GameWindow.java b/robots/src/gui/GameWindow.java index ecb63c0..9adfa15 100644 --- a/robots/src/gui/GameWindow.java +++ b/robots/src/gui/GameWindow.java @@ -1,20 +1,25 @@ package gui; import java.awt.BorderLayout; - import javax.swing.JInternalFrame; import javax.swing.JPanel; -public class GameWindow extends JInternalFrame -{ - private final GameVisualizer m_visualizer; - public GameWindow() - { +public class GameWindow extends JInternalFrame { + private final RobotModel model; + private final GameVisualizer visualizer; + private final RobotInfoWindow infoWindow; + + public GameWindow() { super("Игровое поле", true, true, true, true); - m_visualizer = new GameVisualizer(); + model = new RobotModel(); + visualizer = new GameVisualizer(model); + infoWindow = new RobotInfoWindow(model); + JPanel panel = new JPanel(new BorderLayout()); - panel.add(m_visualizer, BorderLayout.CENTER); + panel.add(visualizer, BorderLayout.CENTER); getContentPane().add(panel); pack(); } -} + + public RobotInfoWindow getInfoWindow() { return infoWindow; } +} \ No newline at end of file diff --git a/robots/src/gui/LogWindow.java b/robots/src/gui/LogWindow.java index 901d8df..0275edb 100644 --- a/robots/src/gui/LogWindow.java +++ b/robots/src/gui/LogWindow.java @@ -9,40 +9,33 @@ import log.LogEntry; import log.LogWindowSource; -public class LogWindow extends JInternalFrame implements LogChangeListener -{ - private LogWindowSource m_logSource; - private TextArea m_logContent; +public class LogWindow extends JInternalFrame implements LogChangeListener { + private final LogWindowSource source; + private final TextArea content; - public LogWindow(LogWindowSource logSource) - { + public LogWindow(LogWindowSource source) { super("Протокол работы", true, true, true, true); - m_logSource = logSource; - m_logSource.registerListener(this); - m_logContent = new TextArea(""); - m_logContent.setSize(200, 500); - + this.source = source; + source.registerListener(this); + content = new TextArea(""); JPanel panel = new JPanel(new BorderLayout()); - panel.add(m_logContent, BorderLayout.CENTER); + panel.add(content, BorderLayout.CENTER); getContentPane().add(panel); pack(); - updateLogContent(); + updateContent(); } - private void updateLogContent() - { - StringBuilder content = new StringBuilder(); - for (LogEntry entry : m_logSource.all()) - { - content.append(entry.getMessage()).append("\n"); - } - m_logContent.setText(content.toString()); - m_logContent.invalidate(); + private void updateContent() { + StringBuilder sb = new StringBuilder(); + for (LogEntry e : source.all()) sb.append(e.getMessage()).append('\n'); + content.setText(sb.toString()); + content.invalidate(); } - @Override - public void onLogChanged() - { - EventQueue.invokeLater(this::updateLogContent); + @Override public void onLogChanged() { EventQueue.invokeLater(this::updateContent); } + + public void close() { + source.unregisterListener(this); + dispose(); } } \ No newline at end of file diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index d2aa0fc..6ed15e4 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -11,12 +11,12 @@ public class MainApplicationFrame extends JFrame { private final AppStateManager stateManager = new AppStateManager(); private static final int DEFAULT_INSET = 50; - private static final int DEFAULT_INTERNAL_WIDTH = 600; - private static final int DEFAULT_INTERNAL_HEIGHT = 400; - private static final int DEFAULT_GAME_X = 10; - private static final int DEFAULT_GAME_Y = 10; - private static final int DEFAULT_LOG_X = 220; - private static final int DEFAULT_LOG_Y = 10; + private static final int DEFAULT_INTERNAL_W = 600; + private static final int DEFAULT_INTERNAL_H = 400; + private static final int DEFAULT_LOG_X = 220, DEFAULT_LOG_Y = 10; + private static final int DEFAULT_GAME_X = 10, DEFAULT_GAME_Y = 10; + private static final int DEFAULT_INFO_X = 430, DEFAULT_INFO_Y = 10; + private static final int DEFAULT_INFO_W = 230, DEFAULT_INFO_H = 110; public MainApplicationFrame() { stateManager.load(); @@ -26,30 +26,35 @@ public MainApplicationFrame() { int defH = screenSize.height - DEFAULT_INSET * 2; stateManager.restoreMain(this, DEFAULT_INSET, DEFAULT_INSET, defW, defH); - setContentPane(desktopPane); logWindow = createLogWindow(); - stateManager.restoreInternalFrame(logWindow, "log", DEFAULT_LOG_X, DEFAULT_LOG_Y, DEFAULT_INTERNAL_WIDTH, DEFAULT_INTERNAL_HEIGHT); + // Генерируем префикс из заголовка, чтобы он совпадал с сохранением + restoreWindowWithAutoPrefix(logWindow, DEFAULT_LOG_X, DEFAULT_LOG_Y, DEFAULT_INTERNAL_W, DEFAULT_INTERNAL_H); addWindow(logWindow); gameWindow = new GameWindow(); - stateManager.restoreInternalFrame(gameWindow, "game", DEFAULT_GAME_X, DEFAULT_GAME_Y, DEFAULT_INTERNAL_WIDTH, DEFAULT_INTERNAL_HEIGHT); + restoreWindowWithAutoPrefix(gameWindow, DEFAULT_GAME_X, DEFAULT_GAME_Y, DEFAULT_INTERNAL_W, DEFAULT_INTERNAL_H); addWindow(gameWindow); - setJMenuBar(generateMenuBar()); + RobotInfoWindow infoWindow = gameWindow.getInfoWindow(); + restoreWindowWithAutoPrefix(infoWindow, DEFAULT_INFO_X, DEFAULT_INFO_Y, DEFAULT_INFO_W, DEFAULT_INFO_H); + addWindow(infoWindow); + setJMenuBar(new MenuBarBuilder(this).buildMenuBar()); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - exitApplication(); - } + @Override public void windowClosing(java.awt.event.WindowEvent e) { exitApplication(); } }); - Logger.debug("Главное окно инициализировано"); } + // Вспомогательный метод: формирует ключ из заголовка окна и восстанавливает состояние + private void restoreWindowWithAutoPrefix(JInternalFrame frame, int defX, int defY, int defW, int defH) { + String prefix = frame.getTitle().replaceAll("\\s+", "_").toLowerCase(); + stateManager.restoreInternalFrame(frame, prefix, defX, defY, defW, defH); + } + protected LogWindow createLogWindow() { LogWindow lw = new LogWindow(Logger.getDefaultLogSource()); Logger.debug("Протокол работает"); @@ -65,34 +70,22 @@ public void exitApplication() { stateManager.saveMain(this); stateManager.saveAllFrames(desktopPane); stateManager.save(); + Logger.debug("Конфигурация сохранена"); - Logger.debug("Конфигурация сохранена перед выходом"); - - UIManager.put("OptionPane.yesButtonText", "Да"); - UIManager.put("OptionPane.noButtonText", "Нет"); - int result = JOptionPane.showConfirmDialog( - this, - "Вы действительно хотите выйти?", - "Подтверждение выхода", - JOptionPane.YES_NO_OPTION - ); - if (result == JOptionPane.YES_OPTION) { - Logger.debug("Приложение закрыто пользователем"); + int res = JOptionPane.showConfirmDialog(this, "Вы действительно хотите выйти?", "Выход", JOptionPane.YES_NO_OPTION); + if (res == JOptionPane.YES_OPTION) { + Logger.debug("Приложение закрыто"); System.exit(0); } } - private JMenuBar generateMenuBar() { - return new MenuBarBuilder(this).buildMenuBar(); - } - public void setLookAndFeel(String className) { try { UIManager.setLookAndFeel(className); SwingUtilities.updateComponentTreeUI(this); - Logger.debug("Тема оформления изменена: " + className); + Logger.debug("Тема изменена: " + className); } catch (Exception e) { - Logger.error("Не удалось установить тему оформления: " + e.getMessage()); + Logger.error("Ошибка темы: " + e.getMessage()); } } } \ No newline at end of file diff --git a/robots/src/gui/MenuBarBuilder.java b/robots/src/gui/MenuBarBuilder.java new file mode 100644 index 0000000..51465df --- /dev/null +++ b/robots/src/gui/MenuBarBuilder.java @@ -0,0 +1,48 @@ +package gui; + +import java.awt.event.KeyEvent; +import javax.swing.*; +import log.Logger; + +public class MenuBarBuilder { + private final MainApplicationFrame frame; + public MenuBarBuilder(MainApplicationFrame frame) { this.frame = frame; } + + public JMenuBar buildMenuBar() { + JMenuBar menuBar = new JMenuBar(); + menuBar.add(createFileMenu()); + menuBar.add(createLookAndFeelMenu()); + menuBar.add(createTestMenu()); + return menuBar; + } + + private JMenu createFileMenu() { + JMenu menu = new JMenu("Файл"); + menu.setMnemonic(KeyEvent.VK_F); + JMenuItem exit = new JMenuItem("Выход"); + exit.setMnemonic(KeyEvent.VK_X); + exit.addActionListener(e -> { Logger.debug("Выход из приложения"); frame.exitApplication(); }); + menu.add(exit); + return menu; + } + + private JMenu createLookAndFeelMenu() { + JMenu menu = new JMenu("Режим отображения"); + menu.setMnemonic(KeyEvent.VK_V); + JMenuItem sys = new JMenuItem("Системная схема", KeyEvent.VK_S); + sys.addActionListener(e -> frame.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())); + JMenuItem cross = new JMenuItem("Универсальная схема", KeyEvent.VK_U); + cross.addActionListener(e -> frame.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName())); + menu.add(sys); menu.add(cross); + return menu; + } + + private JMenu createTestMenu() { + JMenu menu = new JMenu("Тесты"); + menu.setMnemonic(KeyEvent.VK_T); + JMenuItem logMsg = new JMenuItem("Сообщение в лог", KeyEvent.VK_L); + logMsg.addActionListener(e -> Logger.debug("Тестовое сообщение")); + menu.add(logMsg); + return menu; + } +} \ No newline at end of file diff --git a/robots/src/gui/RobotInfoWindow.java b/robots/src/gui/RobotInfoWindow.java new file mode 100644 index 0000000..5a506c6 --- /dev/null +++ b/robots/src/gui/RobotInfoWindow.java @@ -0,0 +1,53 @@ +package gui; + +import java.awt.BorderLayout; +import java.awt.EventQueue; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; + +public class RobotInfoWindow extends JInternalFrame implements RobotModel.Observer { + private final RobotModel model; + private final JLabel lblPos; + private final JLabel lblTarget; + private final JLabel lblDir; + + public RobotInfoWindow(RobotModel model) { + super("Координаты робота", true, true, true, true); + this.model = model; + model.addObserver(this); + + JPanel panel = new JPanel(new BorderLayout(5, 5)); + lblPos = new JLabel("Позиция: (0, 0)"); + lblTarget = new JLabel("Цель: (0, 0)"); + lblDir = new JLabel("Направление: 0°"); + + panel.add(lblPos, BorderLayout.NORTH); + panel.add(lblTarget, BorderLayout.CENTER); + panel.add(lblDir, BorderLayout.SOUTH); + getContentPane().add(panel); + pack(); + setSize(230, 110); + + // Вызываем метод обновления меток + updateLabels(); + } + + // Переименовано из updateUI, чтобы не конфликтовать со системным методом Swing + private void updateLabels() { + lblPos.setText(String.format("Позиция: (%.1f, %.1f)", model.getX(), model.getY())); + lblTarget.setText(String.format("Цель: (%d, %d)", model.getTargetX(), model.getTargetY())); + lblDir.setText(String.format("Направление: %.1f°", Math.toDegrees(model.getDir()))); + } + + @Override + public void onStateChanged(double x, double y, double dir, int tx, int ty) { + // Обновляем метки в потоке событий при изменении модели + EventQueue.invokeLater(this::updateLabels); + } + + public void close() { + model.removeObserver(this); + dispose(); + } +} \ No newline at end of file diff --git a/robots/src/gui/RobotModel.java b/robots/src/gui/RobotModel.java new file mode 100644 index 0000000..2f32bfb --- /dev/null +++ b/robots/src/gui/RobotModel.java @@ -0,0 +1,81 @@ +package gui; + +import java.util.ArrayList; +import java.util.List; + +public class RobotModel { + public interface Observer { + void onStateChanged(double x, double y, double dir, int tx, int ty); + } + + private final List observers = new ArrayList<>(); + private volatile double x = 100, y = 100, dir = 0; + private volatile int targetX = 150, targetY = 100; + + private static final double MAX_V = 0.1; + private static final double MAX_W = 0.001; + + public void addObserver(Observer o) { + synchronized(observers) { observers.add(o); } + } + public void removeObserver(Observer o) { + synchronized(observers) { observers.remove(o); } + } + + private void notifyObservers() { + List snapshot; + synchronized(observers) { snapshot = new ArrayList<>(observers); } + for (Observer o : snapshot) { + o.onStateChanged(x, y, dir, targetX, targetY); + } + } + + public double getX() { return x; } + public double getY() { return y; } + public double getDir() { return dir; } + public int getTargetX() { return targetX; } + public int getTargetY() { return targetY; } + + public void setTarget(int tx, int ty) { + targetX = tx; + targetY = ty; + } + + public void update() { + double dx = targetX - x; + double dy = targetY - y; + double dist = Math.hypot(dx, dy); + if (dist < 0.5) return; + + double angleToTarget = Math.atan2(dy, dx); + while (angleToTarget < 0) angleToTarget += 2 * Math.PI; + while (angleToTarget >= 2 * Math.PI) angleToTarget -= 2 * Math.PI; + + double diff = angleToTarget - dir; + // Исправление бага: всегда поворачиваем кратчайшим путем + while (diff > Math.PI) diff -= 2 * Math.PI; + while (diff < -Math.PI) diff += 2 * Math.PI; + + double angularV = Math.abs(diff) < 0.01 ? 0 : Math.signum(diff) * MAX_W; + move(MAX_V, angularV, 10); + } + + private void move(double v, double w, double dt) { + double newX, newY; + if (Math.abs(w) < 1e-6) { + newX = x + v * dt * Math.cos(dir); + newY = y + v * dt * Math.sin(dir); + } else { + newX = x + (v / w) * (Math.sin(dir + w * dt) - Math.sin(dir)); + newY = y - (v / w) * (Math.cos(dir + w * dt) - Math.cos(dir)); + } + x = newX; + y = newY; + dir = dir + w * dt; + while (dir < 0) dir += 2 * Math.PI; + while (dir >= 2 * Math.PI) dir -= 2 * Math.PI; + + notifyObservers(); + // Logger.debug(...) удален, чтобы не засорять протокол + } +} \ No newline at end of file diff --git a/robots/src/gui/WindowConfigManager.java b/robots/src/gui/WindowConfigManager.java index 3cb7a07..5e96182 100644 --- a/robots/src/gui/WindowConfigManager.java +++ b/robots/src/gui/WindowConfigManager.java @@ -1,4 +1,5 @@ package gui; + import java.io.*; import java.util.Properties; import log.Logger; @@ -10,39 +11,34 @@ public class WindowConfigManager { public WindowConfigManager() { file = new File(System.getProperty("user.home"), FILE_NAME); - } public void load() { if (file.exists()) { try (FileInputStream fis = new FileInputStream(file)) { props.load(fis); - Logger.debug("Конфигурация загружена успешно"); + Logger.debug("Конфиг загружен"); } catch (IOException e) { - Logger.error("Не удалось загрузить конфигурацию: " + e.getMessage()); + Logger.error("Ошибка загрузки конфига: " + e.getMessage()); } } else { - Logger.debug("Файл конфигурации не найден, используются значения по умолчанию"); + Logger.debug("Конфиг не найден, используются дефолтные значения"); } } public void save() { try (FileOutputStream fos = new FileOutputStream(file)) { - props.store(fos, "Application Window Configuration"); - + props.store(fos, "App Config"); + Logger.debug("Конфиг сохранен"); } catch (IOException e) { - Logger.error("Не удалось сохранить конфигурацию: " + e.getMessage()); + Logger.error("Ошибка сохранения конфига: " + e.getMessage()); } } public int getInt(String key, int def) { String val = props.getProperty(key); - try { - return val != null ? Integer.parseInt(val) : def; - } catch (NumberFormatException e) { - Logger.error("Неверный формат числа для ключа '" + key + "': " + val); - return def; - } + try { return val != null ? Integer.parseInt(val) : def; } + catch (NumberFormatException e) { Logger.error("Ошибка парсинга " + key); return def; } } public boolean getBool(String key, boolean def) { @@ -58,12 +54,12 @@ public void saveMain(int x, int y, int w, int h, int state) { props.setProperty("main.state", String.valueOf(state)); } - public void saveInternal(String prefix, int x, int y, int w, int h, boolean iconified, boolean maximized) { + public void saveInternal(String prefix, int x, int y, int w, int h, boolean icon, boolean max) { props.setProperty(prefix + ".x", String.valueOf(x)); props.setProperty(prefix + ".y", String.valueOf(y)); props.setProperty(prefix + ".w", String.valueOf(w)); props.setProperty(prefix + ".h", String.valueOf(h)); - props.setProperty(prefix + ".icon", String.valueOf(iconified)); - props.setProperty(prefix + ".max", String.valueOf(maximized)); + props.setProperty(prefix + ".icon", String.valueOf(icon)); + props.setProperty(prefix + ".max", String.valueOf(max)); } } \ No newline at end of file diff --git a/robots/src/log/LogWindowSource.java b/robots/src/log/LogWindowSource.java index ca0ce44..acfca54 100644 --- a/robots/src/log/LogWindowSource.java +++ b/robots/src/log/LogWindowSource.java @@ -2,88 +2,60 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.List; -/** - * Что починить: - * 1. Этот класс порождает утечку ресурсов (связанные слушатели оказываются - * удерживаемыми в памяти) - * 2. Этот класс хранит активные сообщения лога, но в такой реализации он - * их лишь накапливает. Надо же, чтобы количество сообщений в логе было ограничено - * величиной m_iQueueLength (т.е. реально нужна очередь сообщений - * ограниченного размера) - */ -public class LogWindowSource -{ - private int m_iQueueLength; - - private ArrayList m_messages; - private final ArrayList m_listeners; - private volatile LogChangeListener[] m_activeListeners; - - public LogWindowSource(int iQueueLength) - { - m_iQueueLength = iQueueLength; - m_messages = new ArrayList(iQueueLength); - m_listeners = new ArrayList(); +public class LogWindowSource { + private final int maxQueueLength; + private final List messages = new ArrayList<>(); + private final List listeners = new ArrayList<>(); + private volatile LogChangeListener[] activeListeners; + + public LogWindowSource(int queueLength) { + this.maxQueueLength = queueLength; } - - public void registerListener(LogChangeListener listener) - { - synchronized(m_listeners) - { - m_listeners.add(listener); - m_activeListeners = null; + + public void registerListener(LogChangeListener listener) { + synchronized(listeners) { + listeners.add(listener); + activeListeners = null; } } - - public void unregisterListener(LogChangeListener listener) - { - synchronized(m_listeners) - { - m_listeners.remove(listener); - m_activeListeners = null; + + public void unregisterListener(LogChangeListener listener) { + synchronized(listeners) { + listeners.remove(listener); + activeListeners = null; } } - - public void append(LogLevel logLevel, String strMessage) - { - LogEntry entry = new LogEntry(logLevel, strMessage); - m_messages.add(entry); - LogChangeListener [] activeListeners = m_activeListeners; - if (activeListeners == null) - { - synchronized (m_listeners) - { - if (m_activeListeners == null) - { - activeListeners = m_listeners.toArray(new LogChangeListener [0]); - m_activeListeners = activeListeners; - } - } - } - for (LogChangeListener listener : activeListeners) - { - listener.onLogChanged(); + + public void append(LogLevel level, String message) { + synchronized(listeners) { + messages.add(new LogEntry(level, message)); + while (messages.size() > maxQueueLength) messages.remove(0); } - } - - public int size() - { - return m_messages.size(); + notifyListeners(); } - public Iterable range(int startFrom, int count) - { - if (startFrom < 0 || startFrom >= m_messages.size()) - { - return Collections.emptyList(); + private void notifyListeners() { + LogChangeListener[] current = activeListeners; + if (current == null) { + synchronized(listeners) { + if (activeListeners == null) { + current = listeners.toArray(new LogChangeListener[0]); + activeListeners = current; + } + } + } + for (LogChangeListener l : current) { + try { l.onLogChanged(); } catch (Exception ignored) {} } - int indexTo = Math.min(startFrom + count, m_messages.size()); - return m_messages.subList(startFrom, indexTo); } - public Iterable all() - { - return m_messages; + public int size() { return messages.size(); } + public Iterable all() { return new ArrayList<>(messages); } + public Iterable range(int from, int count) { + if (from < 0 || from >= messages.size()) return Collections.emptyList(); + int to = Math.min(from + count, messages.size()); + return messages.subList(from, to); } -} +} \ No newline at end of file